pythonpytestpytest-fixtures

How to access a fixture inside non-fixture function in pytest


I tried to pass the list of test data file paths as a command line argument. However, I have ended up with following code block:

From conftest.py file:

import json

from pytest import fixture

def pytest_addoption(parser):
    parser.addoption(
        "--test-data-path",
        action="store",
        default="test_data/test_data.json", # not suggested
        help="Path of test data file"
    )

@fixture(scope='session')
def get_test_data_path(request):
    return request.config.getoption("--test-data-path")

def load_test_data(path=get_test_data_path):
    with open(path) as test_data_file:
        return json.load(test_data_file)


@fixture(scope="session", params=load_test_data()["body_types"])
def get_body_list(request):
    body_type = request.param
    yield body_type

The content of the test_data/test_data.json:

{
    "body_types": ["coupes", "cabriolets"]
}

It seems like problem is caused, since I am not able to access fixtures inside a non-fixture functions.

Please correct me if I am missing sth

I have tried to write load_test_data function in different ways, such as:

import json

from pytest import fixture

def load_test_data(path):
    with open(path) as test_data_file:
        return json.load(test_data_file)

@fixture(scope='session')
def get_test_data_path(request):
    return request.config.getoption("--test-data-path")

@fixture(scope="session", params=load_test_data(get_test_data_path)["body_types"])
def get_body_list(request):
    body_type = request.param
    yield body_type

However, nothing has changed.


Solution

  • The problem is that when the module is loaded, so is the wrappers. So that means what the load_test_data receive is just the function call just like you also figured out.

    I still haven't had any luck figuring out how you do this in a nice and esay-to-understand way but take a look here. There are some tricks people have done. https://github.com/pytest-dev/pytest/issues/6374

    I found an old example where i did something like what you want. Here i preload the data from pytest_configure hook and then pass it into a global variable, then when the testcase is loaded, the testdata is then passed from the global variable

    # conftest.py
    test_data = []
    def pytest_configure(config):
        global test_data
        path = "./test_data.json" # config.getoption("--test-data-path")
        with open(path) as test_data_file:
            test_data = json.load(test_data_file)
    

    Here is my testcase:

    # testcase
    import pytest
    from tests.conftest import test_data
    
    @pytest.mark.parametrize("body", test_data["body_types"])
    def test_pass(body):
        pass