I have some test cases and test data where test data is in JSON array form as below:
{
"valid_data": [
{
"id": "1234",
"name": "John"
},
{
"id": "2234",
"name": "Mary"
},
{
"id": "3234",
"name": "Kenny"
},
],
"invalid_data": [
{
"id": "1234",
"name": "Mary"
},
{
"id": "2234",
"name": "Kenny"
},
{
"id": "3234",
"name": "John"
},
]
}
I am now testing an API which will take in JSON as input and will respond with a status code. If the id and name match inside the database, it will respond with 200 OK. Else with 400 Bad Request.
So here are my current test cases:
def get_test_data(filename):
folder_path = os.path.abspath(Path(os.path.dirname(__file__)))
folder = os.path.join(folder_path, 'TestData')
jsonfile = os.path.join(folder, filename)
with open(jsonfile) as file:
data = json.load(file)
return data
def test_valid_ok(database_api):
data = get_test_data('test_data.json')
response = database_api.get_user_info(data)
assert requests.codes['ok'] == response.status_code
In my conftest I just declared the method database_api
and take in the URL as the parameter then it will send a post request to the api. For this part had no problem I have tested which is working fine.
However with current structure and code, I can only have 1 json data inside the json file. I would like to have a data-driven test which able to run multiple times based on my test data inside the json file.
I have checked the pytest official documents and various online sources which suggest to use pytest parametrized function but I couldn't get it right with json file.
Thanks if anyone could help!
You can use pytest_generate_tests hook for parametrizing with dynamic data.
First create a fixture that can be called by the test function to get the test data.
# in conftest.py
@pytest.fixture()
def test_data(request):
return request.param
Now you can parametrize it so that it is called for each test data set:
#in conftest.py
def pytest_generate_tests(metafunc):
testdata = get_test_data('test_data.json')
metafunc.parametrize('test_data', testdata, indirect=True)
The testdata
passed to the parametrize
function has to be a list. So you need to modify the input data a bit before passing it. I modified the get_test_data
function a bit.
#in conftest.py
def get_test_data(filename):
folder_path = os.path.abspath(os.path.dirname(__file__))
folder = os.path.join(folder_path, 'TestData')
jsonfile = os.path.join(folder, filename)
with open(jsonfile) as file:
data = json.load(file)
valid_data = [(item, 1) for item in data['valid_data']]
invalid_data = [(item, 0) for item in data['invalid_data']]
# data below is a list of tuples, with first element in the tuple being the
# arguments for the API call and second element specifies if this is a test
# from valid_data set or invalid_data. This can be used for putting in the
# appropriate assert statements for the API response.
data = valid_data + invalid_data
return data
And now your test function could look like:
#in test_API.py
def test_(test_data):
response = database_api.get_user_info(test_data[0])
# Add appropriate asserts.
# test_data[1] == 1 means 200 response should have been received
# test_data[1] == 0 means 400 response should have been received