7

I have been over and over the documentation, but I can not fine out how I get py.test to write to the log for tests that pass. For example if I run "py.test --resultlog=mylog.txt myPytest.py" mylog.txt only has one line for each test that passed. I want to add other things to each test recorded in my log file, regardless whether thy passed or failed. For example I need to know the time they ran, some of the output data etc. How do I get py.test to include data about the test (passed and failed) in the py.test log file?

user3750195
  • 71
  • 1
  • 4

4 Answers4

4

See All Test Output: pytest -rP

The correct way to display the log output of passing tests is outlined in this answer:

pytest -rP

See All Test Output Always: Live Logs

There is also a way to configure Live Logs which I haven't used, but it appears a way to always see the log output of all running tests. The default value for Live Logs is False.

To enable them, edit your configuration file such as pyproject.toml:

[pytest]
log_cli = True

See All Output of Failing Tests: pytest -s

pytest also supports the -s argument to prevent capturing logging calls for failing tests, however.

pytest -s

From the documentation:

-s, –capture=no Normally stdout and stderr are captured and only shown for failing tests. The -s option can be used to disable capturing, showing stdcalls for print statements, logging calls, etc.

Braindead: Make Your Tests Fail

You can make your test fail with an intentional bug to see the output with -s, but this often doesn't show any output. Often works in a pinch when you can't remember pytest -rP :)

Sometimes though, logs triggered by -s this way just won't display, such as in the following instance (for humor):

logger.debug(f"len(new_df) == {len(new_df)}")
logger.error(f"len(new_df) == {len(new_df)}")
logging.debug(f"len(new_df) == {len(new_df)}")
logging.error(f"len(new_df) == {len(new_df)}")
print(f"len(new_df) == {len(new_df)}")
print(f"len(new_df) == {len(new_df)}", sys.stderr)
sys.stderr.write(f"len(new_df) == {len(new_df)}")
sys.stderr.flush()

assert False

No test output went to console :D

rjurney
  • 4,824
  • 5
  • 41
  • 62
Dylan Hogg
  • 3,118
  • 29
  • 26
  • This only works for tasks that fail. You can `assert False` at the end of your test, but this often fails to actually log anything... for a magical reason I don't understand. I tried logging.error, a logger.error, print, print to stderr, sys.write, sys.write to stderr, flushing... no, -s is not how to do this. – rjurney Apr 14 '23 at 01:55
  • @Dylan_Hogg I reworked your answer to be correct based on https://stackoverflow.com/questions/14405063/how-can-i-see-normal-print-output-created-during-pytest-run – rjurney Apr 14 '23 at 02:09
1

You can have a look if the junitxml output provides any more information. But I suspect that if you want the actual time rather then duration etc you will have to write your own plugin. The documentation gives you the relevant hooks: http://pytest.org/latest/plugins.html?highlight=hooks#reporting-hooks

flub
  • 5,953
  • 27
  • 24
0

you could use py-cov combine with pytest

py.test --cov $(MOD_NAME) --cov-config .coveragerc --cov-report xml --junit-xml=results.xml

and here you will get all the info you need as we are used to push the coverage.xml file to sonarqube and get all the data available.

If you do really need customized data/logs coming from your tests functions just pass -s so pytest will stop catching the output and it will print it on the console (and you can stream it to a file maybe, not that nice)

shipperizer
  • 1,641
  • 1
  • 13
  • 19
0

This hook is an experimental and it is called whenever the assertion passes. From documentation-

Use this hook to do some processing after a passing assertion. The original assertion information is available in the orig string and the pytest introspected assertion information is available in the expl string.

This hook must be explicitly enabled by the enable_assertion_pass_hook ini-file option:

[pytest]
enable_assertion_pass_hook=true

You need to clean the .pyc files in your project directory and interpreter libraries when enabling this option, as assertions will require to be re-written.

import logging
log = logging.getLogger(__name__)
def pytest_assertion_pass(item, lineno, orig, expl):
   """
      Prints the log(log file) every time the assert passes
   """
   log.info(str(item) + ' | lineno: ' + str(lineno) + ' | ' + orig + ' | PASS')
sagar
  • 379
  • 4
  • 13