I am testing a function that writes to a log file (it doesnโt matter what it writes to the log file specifically, it can do something, this is just what generated this question)
Something like that:
def do_stuff(): with open('/tmp/mylogs.txt', 'a') as f: f.write(str(time.time())) f.write(' stuff done! \n') return 42
And I can check it something like this:
def test_doing_stuff(watch_logs): assert do_stuff() == 42 assert do_stuff() == 43
For debugging purposes, when the test fails, I want to be able to print new log entries - I can make the device a bit as follows:
@pytest.fixture() def watch_logs(request): with open('/tmp/mylogs.txt') as f: log_before = f.read() def get_new_logs(): with open('/tmp/mylogs.txt') as f: log_after = f.read() return log_after.replace(log_before, '') return get_new_logs
Great - now I can check the contents of the log at any time in my tests:
def test_doing_stuff(watch_logs): assert do_stuff() == 42 print(watch_logs()) assert do_stuff() == 43 print(watch_logs())
Hm - ah, but this second print will not work, it is after a test failure.
What if my test fixture always printed logs at the end of the test? Then the pytest stdout capture will show it to me when it fails, but not when it passes!
@pytest.fixture() def watch_logs(request): with open('/tmp/mylogs.txt') as f: log_before = f.read() def get_new_logs(): with open('/tmp/mylogs.txt') as f: log_after = f.read() return log_after.replace(log_before, '') def print_new_logs(): print('~' * 20 + ' logs ' + '~' * 20) print(get_new_logs()) print('~' * 50) request.addfinalizer(print_new_logs) return get_new_logs
Oh, but it doesnโt work because the capture of the pytests log does not occur during test finalizers.
So the question is: how can I make a test finalizer that can print material?
Here's the ultra-minimal meaning of no (non-essential) material for logging: https://gist.github.com/hjwp/5154ec40a476a5c01ba6