turbonerd
turbonerd

Reputation: 1306

Using a function to provide parameters for pytest test

I have a basic endpoint test which I'm running with pytest filename.py:

ENDPOINTS = ['/users']

def test_get_requests(application_headers):
    """ Test all endpoints with a GET method """

    for endpoint in ENDPOINTS:
        response = requests.get(API_URL + endpoint, headers=application_headers)

    assert response.status_code == 200

This uses the ENDPOINTS list and the application_headers fixture to send HTTP requests to specified endpoints and assert their successful status code.

This works fine.

I have a list of endpoints in a remote JSON file, which I want to load in, filter the endpoints from then test instead of using a manually defined ENDPOINTS list.

I've created a fixture like this:

@pytest.fixture(scope='module')
def application_endpoints():
    endpoints = []

    with request.urlopen('https://my.endpoint.file.json') as response:
        if response.getcode() == 200:
            source = response.read()
            data = json.loads(source)

    for path in data["paths"]:
        endpoints.append(path)

    return endpoints

I've then changed my test definition to def test_get_requests(application_headers, application_endpoints), but this results in the error TypeError: can only concatenate str (not "list") to str.

I also tried a different approach, using parametrize, but this fails too:

@pytest.mark.parametrize('endpoint', application_endpoints)
def test_get_requests(application_headers):
    """ Test all endpoints with a GET method """

    for endpoint in ENDPOINTS:
        response = requests.get(API_URL + endpoint, headers=application_headers)

    assert response.status_code == 200

Error on that failure is NameError: name 'application_endpoints' is not defined.

It feels like I'm doing something pretty simple here, and getting it wrong. Am I thinking about this the wrong way, or is my syntax incorrect?

Upvotes: 0

Views: 533

Answers (1)

MrBean Bremen
MrBean Bremen

Reputation: 16805

You can use the parametrize approach, but you cannot use a fixture for the parameters - just use a function. Also, there is some confusion with endpoints and application_headers in your code. Ignoring where application_headers comes from, you can try something like:

def application_endpoints():  # not a fixture!
    endpoints = []
    ...
    return endpoints

@pytest.mark.parametrize('endpoint', application_endpoints())
def test_get_requests(endpoint):
    response = requests.get(API_URL + endpoint, headers=application_headers)
    assert response.status_code == 200

No need to iterate over the endpoints yourself - that is what mark.parametrize already does by creating a separate test for each endpoint.

Upvotes: 2

Related Questions