Skip to content

Instantly share code, notes, and snippets.

@StefRe
Created April 19, 2020 07:58
Show Gist options
  • Save StefRe/cfe8a665a029add8018826d0730ca142 to your computer and use it in GitHub Desktop.
Save StefRe/cfe8a665a029add8018826d0730ca142 to your computer and use it in GitHub Desktop.
Pytest report hooks
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()])
@StefRe
Copy link
Author

StefRe commented Apr 19, 2020

Result:

.	 17 test_with_error_in[none]                      ppp   	setup↴call↴teardown↴ 
E	 17 test_with_error_in[setup]                     f-p   	setup↴[request = ... Exception]
F	 17 test_with_error_in[call]                      pfp   	setup↴call↴teardown↴[resource =...rtionError]
.E	 17 test_with_error_in[teardown]                  ppf   	setup↴call↴teardown↴[request = ... Exception]
E	 17 test_with_error_in[setup+call]                f-p   	setup↴[request = ... Exception]
E	 17 test_with_error_in[setup+teardown]            f-p   	setup↴[request = ... Exception]
FE	 17 test_with_error_in[call+teardown]             pff   	setup↴call↴teardown↴[resource =... Exception]
E	 17 test_with_error_in[setup+call+teardown]       f-p   	setup↴[request = ... Exception]
x	 35 TestNoErrorXfail.test_xfail                   psp x 	wasxfail↴setup↴call↴teardown↴[self = <te...rtionError]
X	 39 TestNoErrorXfail.test_xpass                   ppp x 	wasxfail↴setup↴call↴teardown↴ 
F	 42 TestNoErrorXfail.test_xpass_strict            pfp   	setup↴call↴teardown↴[[XPASS(str...S(strict)]]
x	 46 TestNoErrorXfail.test_xfail_imperative        psp x 	reason: xfail imperative↴setup↴call↴teardown↴[self = <te...9: XFailed]
s	 59 TestNoErrorSkip.test_skip                     s-p   	↴[Skipped: w...t this now]
s	 63 TestNoErrorSkip.test_skip_without_reason      s-p   	↴[Skipped: u...ional skip]
s	 67 TestNoErrorSkip.test_skipif                   s-p   	↴[Skipped: c...tion: True]
s	 71 TestNoErrorSkip.test_skip_imperative          psp   	setup↴call↴teardown↴[Skipped: s...imperative]
s	 84 TestSetupErrorSkip.test_skip                  s-p   	↴[Skipped: w...t this now]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment