Created
April 19, 2020 07:58
-
-
Save StefRe/cfe8a665a029add8018826d0730ca142 to your computer and use it in GitHub Desktop.
Pytest report hooks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pytest | |
# ----- general ----- | |
@pytest.fixture(scope="function", | |
params=['none', 'setup', 'call', 'teardown', 'setup+call', | |
'setup+teardown', 'call+teardown', 'setup+call+teardown']) | |
def resource(request): | |
param = request.param | |
print('setup') | |
if 'setup' in param: | |
raise Exception('setup') | |
yield param | |
print('teardown') | |
if 'teardown' in param: | |
raise Exception('teardown') | |
def test_with_error_in(resource): | |
print('call') | |
assert 'call' not in resource | |
@pytest.fixture(scope='class') | |
def error_fixture(): | |
assert 0 | |
# ----- xfail ----- | |
@pytest.mark.xfail | |
class TestNoErrorXfail: | |
def setup_method(self): | |
print('setup') | |
def teardown_method(self): | |
print('teardown') | |
def test_xfail(self): | |
print('call') | |
assert False | |
def test_xpass(self): | |
print('call') | |
@pytest.mark.xfail(strict=True) | |
def test_xpass_strict(self): | |
print('call') | |
def test_xfail_imperative(self): | |
print('call') | |
pytest.xfail("xfail imperative") | |
# ----- skip ----- | |
class TestNoErrorSkip: | |
def setup_method(self): | |
print('setup') | |
def teardown_method(self): | |
print('teardown') | |
@pytest.mark.skip(reason="we don't want to test this now") | |
def test_skip(self): | |
print('call') | |
@pytest.mark.skip | |
def test_skip_without_reason(self): | |
print('call') | |
@pytest.mark.skipif('True') | |
def test_skipif(self): | |
print('call') | |
def test_skip_imperative(self): | |
print('call') | |
pytest.skip("skip imperative") | |
class TestSetupErrorSkip: | |
def setup_method(self): | |
print('setup') | |
raise Exception('setup') | |
def teardown_method(self): | |
print('teardown') | |
@pytest.mark.skip(reason="we don't want to test this now") | |
def test_skip(self): | |
print('call') | |
############################################################################## | |
class HookPlugin(): | |
outcome = '' | |
sections = [] | |
duration = 0 | |
longrepr = '' | |
wasxfail = False | |
def pytest_runtest_logreport(self, report): | |
if self.outcome: | |
self.outcome += '-' | |
self.outcome += '{}:{}'.format(report.when, report.outcome) | |
self.sections = report.sections # is already accumulated over phases | |
if report.when == 'call': | |
self.duration = report.duration | |
if report.longreprtext: | |
self.longrepr += report.longrepr[2] if isinstance(report.longrepr, tuple) else report.longreprtext | |
if hasattr(report, 'wasxfail'): | |
self.wasxfail = report.wasxfail if report.wasxfail else 'wasxfail' | |
def pytest_runtest_logfinish(self, nodeid, location): | |
verbose = False | |
sep = '↴' | |
if verbose: | |
print('\n ====== LOGFINISHED =======') | |
print(f' |nodeid : {nodeid}') | |
print(f' |outcome : {self.outcome}') | |
print(f' |sections : {self.sections}') | |
print(f' |duration : {self.duration}') | |
print(f' |longrepr : {self.longrepr}') | |
print(f' |location : {location}') | |
print(f' |wasxfail : {self.wasxfail}') | |
print(' ==========================') | |
else: | |
outcome = list('---') | |
for oc in self.outcome.split('-'): | |
when, res = oc.split(':') | |
outcome[{'s': 0, 'c': 1, 't': 2}[when[0]]] = res[0] | |
outcome = ''.join(outcome) | |
if self.longrepr: | |
lr = self.longrepr.split('\n') | |
longrepr = f'[{lr[0][:10]}...{lr[-1][-10:]}]' | |
else: | |
longrepr = ' ' | |
print(f'\t{location[1]:>3} {location[2]:<45} ' | |
f'{outcome} {f"x {chr(9)}{self.wasxfail}{sep}" if self.wasxfail else f" {chr(9)}"}' | |
f'{sep.join([s[1].rstrip() for s in self.sections])}' + | |
(f'{sep}{longrepr}' if longrepr else '')) | |
self.outcome = '' | |
self.longrepr = '' | |
self.duration = 0 | |
self.wasxfail = False | |
if __name__ == '__main__': | |
pytest.main([__file__, '--disable-pytest-warnings'], plugins=[HookPlugin()]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Result: