'Create dynamic parameters with pytest?
I am attempting to test various endpoints of my REST API. Some of the end points take values that are provided by other end points. For example:
- Query
/locations
to get a list of available locations and if they are enabled - Query
/inventory?loc_id=<id>
and pass in a location ID to get a list of inventory at specific location - Query
/inventory/<id>/details
to get a list of attributes associated with one particular inventory ID
In my tests, I want to walk this entire work flow (checking specific attributes of inventory items at specific locations). Normally, I'd build a pytest function with a couple @parameterize
decorators, but in this case, I don't know all the IDs ahead of time.
What I'd normally do:
@pytest.mark.parametrize('location', ['1', '2', '3', 'HQ'])
@pytest.mark.parametrize('inventory_id', [1, 2, 3])
def test_things(location, inventory_id):
# Call /inventory/inventory_id/details and check attributes
That second line is a problem because I don't know the inventory_id
s without calling /inventory
first. It's also entirely possible that the inventory_id
isn't available at a specific location.
What I'd like to do:
Query /location to build a list of IDs to add to the first parameterize line
Query `/inventory?loc_id=<id>` and build a list of IDs to pass to the second parameterize line
How can I dynamically build these lines?
Solution 1:[1]
If it's really the case that you want to test each location with each inventory_id you can just calculate those lists ahead of test
def get_locations_list(...):
locations = []
# query locations
...
return locations
LOCATIONS = get_locations_list()
INVENTORY_IDS = get_inventory_ids()
@pytest.mark.parametrize('location', LOCATIONS)
@pytest.mark.parametrize('inventory_id', INVENTORY_IDS)
def test_things(location, inventory_id):
# test stuff
If inventory ids depend on location then you can prepare list of tuples:
def get_locations_and_ids():
list_of_tuples = []
...
for location in locations:
ids = ...
for id in ids:
list_of_tuples.append( (location, id) )
return list_of_tuples
LIST_OF_TUPLES = get_locations_and_ids()
@pytest.mark.parametrize(('location', 'inventory_id'), LIST_OF_TUPLES)
def test_things(location, inventory_id):
# ...
You can also use pytest-generate-tests pattern as described in:
https://docs.pytest.org/en/latest/parametrize.html#basic-pytest-generate-tests-example
Solution 2:[2]
You can try pytest.fixtures to create context for your test check out the documentation here
In this case you can generate any object/value that you need for example:
import pytest
@pytest.fixture
def inventory_id():
return InventoryObject.id
Other Option is to use the vcrpy package. This allow you to record a real HTTP call and save it in a file.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Karol Zlot |
Solution 2 | Ciszko |