HomeContact
Python
Using Fixtures to create API request body dynamically
Karthikeya
October 07, 2021
1 min

Using Fixtures to create API request body

Fixtures in pytest are very versatile, combine them with closures they become very powerful. Let us write a fixture for creating an API request body dynamically using a combination of a closure fixture.

The API we are using is a POST endpoint at https://gorest.co.in/public/v1/user. The API creates a new user in the system. the request body looks something like this.

{
    "name": "name",
    "email": "dummy@email.com",
    "status": "active",
    "gender": "male"
}

Now if we have to create multiple users, we can use the parameterize construct to manage the creation of users. But the question is, how to provide the request body to the tests. Well, the easier approach would be to simply add a payload for every request in the parameterize call.


@pytest.mark.parameterize("request", [
    ({
         "name": "name",
         "email": "dummy@email.com",
         "status": "active",
         "gender": "male"
     },
     {
         "name": "name2",
         "email": "dummy2@email.com",
         "status": "active",
         "gender": "male"
     })
])
def test_create_user(build_request_body,
                     base_url,
                     authorization_token,
                     request_body):
    url = f"{base_url}/users"
    header = {"Authorization": authorization_token}
    response = requests.post(url=url, data=request_body, headers=header)
    assert response.status_code == 200

This approach makes the test very clumsy and is not recommended and unmaintainable. Another approach is to create a closure fixture to dynamically generate the request body. We can leverage the conftest.py file to create this fixture.


@pytest.fixture(scope='session')
def build_request_body():
    def _build(name, email, status, gender):
        return {
            "name": name,
            "email": email,
            "status": status,
            "gender": gender
        }

    return _build

Observing the code, we can see that a function is wrapped inside another function. Also, the inner function is taking all the arguments necessary for building the request. This is a closure pattern. During the test run, pytest evaluates this fixture and provides the inner function as a callable function object to the test. We can then call this function with the request params received from parameterized calls and dynamically build the request body. Let us now look at the refactored test after the introduction of the build_request_body fixture.


@pytest.mark.parametrize(("name", "email", "status", "gender"), [
    ("mark", "mark@smith.com", "active", "male"),
    ("steve", 'steve@email.com', "active", "male")
])
def test_create_user(build_request_body,
                     base_url,
                     authorization_token,
                     name,
                     email,
                     status,
                     gender):
    api_request = build_request_body(name=name, email=email, status=status, gender=gender)
    url = f"{base_url}/users"
    header = {"Authorization": authorization_token}
    response = requests.post(url=url, data=api_request, headers=header)
    assert response.status_code == 200

Now the tests are much more manageable, if we want to improve the code further, we can inject the test data from a json file

Complete code will look something like this.

conftest.py


@pytest.fixture(scope='session')
def build_request_body():
    def _build(name, email, status, gender):
        return {
            "name": name,
            "email": email,
            "status": status,
            "gender": gender
        }

    return _build


@pytest.fixture(scope='session')
def base_url():
    return "https://gorest.co.in/public/v1"


@pytest.fixture(scope="session")
def authorization_token():
    return "Bearer YOUR_BEARER_TOKEN"


gorest.py


@pytest.mark.parametrize(("name", "email", "status", "gender"), [
    ("mark", "mark@smith.com", "active", "male"),
    ("steve", 'steve@email.com', "active", "male")
])
def test_create_user(build_request_body,
                     base_url,
                     authorization_token,
                     name,
                     email,
                     status,
                     gender):
    api_request = build_request_body(name=name, email=email, status=status, gender=gender)
    url = f"{base_url}/users"
    header = {"Authorization": authorization_token}
    response = requests.post(url=url, data=api_request, headers=header)
    assert response.status_code == 201


Related Posts

Deep comparison of JSON in python
November 18, 2021
1 min
© 2021, All Rights Reserved.

Quick Links

About UsContact UsSite Map

Social Media