Pytest: passing test variable or test file var to @pytest.hookimpl(tryfirst=True, hookwrapper=True)

Viewed 1117

I am working on several custom loggers for pytest to improve the representation of test results as they are being executed. Presently for each iteration of the test I am able to capture test name, state and the parametrized blob. To be able to use custom logger on demand I would like to be able to turn it on per test file, per test or globally from the cli.

Presently when i look at the data in @pytest.hookimpl(tryfirst=True, hookwrapper=True) the test file variables or test variables dont seem to be accessible.

Is there a way to pass specific variable(s) from test file, specific test within test file or globally from the cli to @pytest.hookimpl(tryfirst=True, hookwrapper=True) for example: (log_suite or log_test or cli_log) and log_file?

conftest.py

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    setattr(item, "rep_" + rep.when, rep) # for later use

    if rep.when == 'call':
        data = {'when': rep.when, 'outcome': rep.outcome, 'nodeid':rep.nodeid}

        # the reason loggin is here, as I would like to log every test permutation result as its happening.
        if (log_suite or log_test or cli_log) and log_file: # somehow to get those
            # log logic

test_file.py

import pytest 

log_suite = True
log_file = '/tmp/pytest.log'

@pytest.mark.parametrize('t_params', {300_permutations})
def test_permutations(t_params):
    log_test = True

    # some test logic ...
1 Answers

You can access module-level variables in hooks via item.module, e.g.

def pytest_runtest_makereport(item, call):
    yield
    log_file = item.module.log_file
    log_suite = item.module.log_suite
    ...

etc. You won't be able to access variables from function local scope though, they're already gone by that time. You can assign them to a module yourself, e.g. to pytest:

def test_permutations(t_params):
    pytest.log_test = True

def pytest_runtest_makereport(item, call):
    yield
    log_test = pytest.log_test

or to your current test module:

def test_permutations(t_params):
    globals()['log_test'] = True

def pytest_runtest_makereport(item, call):
    yield
    log_test = item.module.log_test

or use anything that's defined globally, for example, the cache:

def test_permutations(t_params, request):
    log_test = True
    request.config.cache.set('log_test', log_test)

def pytest_runtest_makereport(item, call):
    yield
    log_test = item.session.config.cache.get('log_test', None)

BTW there's no such hook as pytest_runtest_logger, double-check that name or the tests won't be runnable. Here's the reference of all hooks available.

Related