Here’s the thing:
I have an Array2D class that receives parameters ‘shape’ and ‘val’. The constructor is as follows:
class Array2D: ... def __init__(self, shape: tuple, val): self.shape = shape self.size = self.shape[0] * self.shape[1] self.data = [val] * self.size ...
I would like to perform tests on this class. To do this I have declared a variable ARRAY_CONFIG, which lists parameters for different two-dimensional arrays. Here is an example:
ARRAY_CONFIG = [ [(2, 3), 3], [(2, 3), 1.7] ]
I have also defined other lists that store the expected values for future tests. Take a look:
SIZE = [6, 6] DATA = [ [3, 3, 3, 3, 3, 3], [1.7, 1.7, 1.7, 1.7, 1.7, 1.7] ]
Now I want to build a test function that by the parameterization decorator, makes comparison between these lists. Here is an example without the decorators from the PyTest library:
def test_size_and_data(): for i in range(len(ARRAY_CONFIG)): array_config = ARRAY_CONFIG[i] size = SIZE[i] data = DATA[i] array = Array2D(*array_config) assert array.size == size assert array.data == data
I managed to develop something, but it seems somewhat repetitive to me. Here it is:
def combine(list1, list2): return [(list1[i], list2[i]) for i in range(len(list1))] @pytest.fixture def array(request): return Array2D(*request.param) @pytest.mark.parametrize('array, expected', combine(ARRAY_CONFIG, SIZE), indirect=['array']) def test_size(array, expected): assert array.size == expected @pytest.mark.parametrize('array, expected', combine(ARRAY_CONFIG, DATA), indirect=['array']) def test_data(array, expected): assert array.data == expected
What is the best way to perform this kind of test where there is a list of “expected values”? I’ve tried performing two parameterizations, but I end up performing combinations between the values, rather than one-to-one comparisons. As done here:
# Other tests --> generate 4 tests instead of 2 @pytest.fixture(params=ARRAY_CONFIG) def array(request): return Array2D(*request.param) @pytest.fixture def array_size(array): return array.size @pytest.mark.parametrize('expected', SIZE) def test_size(array_size, expected): assert array_size == expected
Thanks in advance.
Advertisement
Answer
It’s much simpler if you use the combine
function as the parameter in parametrize
. You can yield
every set of values
def combine(): for arr, size, data in zip(ARRAY_CONFIG, SIZE, DATA): yield Array2D(*arr), size, data @pytest.mark.parametrize('expected', combine()) def test_size_and_data(expected): array, size, data = expected print(array.size, size) print(array.data, data)
Or more explicit parameters
@pytest.mark.parametrize('array, size, data', combine()) def test_size_and_data(array, size, data): print(array.size, size) print(array.data, data)
Output
example_test.py::test_size_and_data[expected0] PASSED [ 50%] 6 6 [3, 3, 3, 3, 3, 3] [3, 3, 3, 3, 3, 3] example_test.py::test_size_and_data[expected1] PASSED [100%] 6 6 [1.7, 1.7, 1.7, 1.7, 1.7, 1.7] [1.7, 1.7, 1.7, 1.7, 1.7, 1.7] -------------------------------------------------------------- example_test.py::test_size_and_data[array0-6-data0] PASSED [ 50%] 6 6 [3, 3, 3, 3, 3, 3] [3, 3, 3, 3, 3, 3] example_test.py::test_size_and_data[array1-6-data1] PASSED [100%] 6 6 [1.7, 1.7, 1.7, 1.7, 1.7, 1.7] [1.7, 1.7, 1.7, 1.7, 1.7, 1.7]