python-3.xloggingautomated-testspytestteardown

Python logging does not log when used inside a Pytest fixture


I have a Pytest + Selenium project and I would like to use the logging module.

However, when I set up logging in conftest.py like this

@pytest.fixture(params=["chrome"], scope="class")
def init_driver(request):
    start = datetime.now()
    logging.basicConfig(filename='.\\test.log', level=logging.INFO)
    if request.param == "chrome":
        options = ChromeOptions()
        options.add_argument("--start-maximized")
        web_driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
    if request.param == "firefox":
        web_driver = webdriver.Firefox(GeckoDriverManager().install())
    request.cls.driver = web_driver
    yield
    end = datetime.now()
    logging.info(f"{end}: --- DURATION: {end - start}")
    web_driver.close()

looks like test.log is not created at all and there are no error messages or other indications something went wrong.

How can I make this work?


Solution

  • Two facts first:

    1. logging.basicConfig() only has an effect if no logging configuration was done before invoking it (the target logger has no handlers registered).

    2. pytest registers custom handlers to the root logger to be able to capture log records emitted in your code, so you can test whether your program logging behaviour is correct.

    This means that calling logging.basicConfig(filename='.\\test.log', level=logging.INFO) in a fixture will do nothing, since the test run has already started and the root logger has handlers attached by pytest. You thus have two options:

    1. Disable the builtin logging plugin completely. This will stop log records capturing - if you have tests where you are analyzing emitted logs (e.g. using the caplog fixture), those will stop working. Invocation:

      $ pytest -p no:logging ...
      

      You can persist the flag in pyproject.toml so it is applied automatically:

      [tool.pytest.ini_options]
      addopts = "-p no:logging"
      

      Or in pytest.ini:

      [pytest]
      addopts = -p no:logging
      
    2. Configure and use live logging. The configuration in pyproject.toml, equivalent to your logging.basicConfig() call:

      [tool.pytest.ini_options]
      log_file = "test.log"
      log_file_level = "INFO"
      

      In pytest.ini:

      [pytest]
      log_file = test.log
      log_file_level = INFO
      

      Of course, the logging.basicConfig() line can be removed from the init_driver fixture in this case.