potato_programmer
potato_programmer

Reputation: 1

parameterizing pytest tests with fixtures and a command line argument

Trying to take a command line argument (table_name) into pytest (via conftest.py, see below) and use that argument in a helper method to make a query in a DB, and then use query results to create parameterized test inputs using @pytest.mark.parametrize on a test_ function.

#contents of conftest.py
import pytest

def pytest_addoption(parser):
    parser.addoption("--table_name", action="store", default=None, help="enter table name")

@pytest.fixture
def table_name(request):
    return request.config.getoption('--table_name')

Problem is: the command line argument (table_name) is being retrieved using a fixture, and we'd like to pass this into a helper method to make a query and put the query results in a list, but since the helper method takes a fixture, it can't be called outside of another fixture/test_function. So we can't put the list into the parameterized test_function params

#helper method
def get_test_cases(table_name):
    #connect to DB, makes query
    #puts all query results into a list called tests
    return tests

#test function
@pytest.mark.parametrize("columns...", (values...)) #list is read as values
def test_function(columns):
    #assertion tests

Is there any way to use the command line argument and also pass the results of the DB query into the parameterized marker/params?

Upvotes: 0

Views: 1718

Answers (1)

Leo K
Leo K

Reputation: 5364

The description isn't very clear as to how the helper reads the test values from DB or how that helper gets called to produce the values for pytest.mark.parameterize(), but if the helper is capable of getting one test case per call (rather than the whole list at once), then you can make the helper itself a fixture and have it invoked multiple times, once for each test case that is listed in the @pytest.mark.parametrize() decoration. Let's say the database has each test case in a DB row and you index it by some 'test ID' column.

@pytest.fixture
def test_case(request,table_name):
# this is the get-test-case helper, note it is a fixture,
# so it can have table_name as an argument
# request.param will be our test ID here, see the mark.parametrize below
    return query("select * from %s where test_id = %s",
                 (table_name, request.param))

@pytest.mark.parametrize("test_case,p1,p2",
    [ ("TstID1", 1, 2), ("TstID2", 3, 3) ], indirect=["test_case"])
def test_function(test_case, p1, p2):
    # test_case here will be the query result from the call to the test_case() fixture! p1 and p2 will come directly from the parameterize mark.

Note how the regular parameters p1 and p2 are passed as-is, but the one marked as indirect goes through the fixture (this also ensures that the 'expensive' operation of querying the database is performed when the tests are actually run and not when pytest runs the 'collection phase' and prepares the list of tests to run.

Upvotes: 2

Related Questions