Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pytest dynamically parametrized test

Tags:

python

pytest

I have created a 'dynamic' list of parameters which I pass to parametrize.

OPTIONS = ['a', 'b', 'c']

def get_unique_pairs():
    unique_list = []
    for first in OPTIONS:
        for second OPTIONS:
            if first == second:
                continue
            unique_list.append({'first':first, 'second':second))
    return unique_list

def some_func()
    unique_pairs = get_unique_pairs()
    result = []
    for pair in unique_pair:
        if test(pair):
           continue
        else:
           result.append(pair)
    return pair

@pytest.mark.parametrize('param', some_fnc())
def test_fnc(param):
    first = param['first']
    second = param['second']

The input I wish to pass to test_fnc is [('a','b'),('a','c')...('c','b')] where the first and second elements are never the same. There is some additional logic I am using to further remove specific pairs.

When I run the test I get the output:

::test_fnc[param0] PASSED
::test_fnc[param1] PASSED
::test_fnc[param2] PASSED

I have two issues:

  1. I'm not entirely sure how to describe what I am doing to find further documentation / help.
  2. I would like more descriptive output (i.e. not param0), and I'd like to continue using dictionaries to pass data to the test.
like image 535
F. Elliot Avatar asked Jun 12 '18 13:06

F. Elliot


People also ask

How do you run the same test multiple times in pytest?

Repeating a test Each test collected by pytest will be run count times. If you want to override default tests executions order, you can use --repeat-scope command line option with one of the next values: session , module , class or function (default). It behaves like a scope of the pytest fixture.

Can pytest fixtures be parameterized?

pytest. fixture() allows one to parametrize fixture functions.

What is pytest Mark Parametrize do?

The @pytest. mark. parametrize() decorator lets you parameterize arguments of the testing function independent of fixtures you created.


1 Answers

I would write it like this:

import pytest
import itertools


OPTIONS = ['a', 'b', 'c']

@pytest.mark.parametrize(
    'param',
    itertools.permutations(OPTIONS, 2),
    ids=lambda pair: "first={}, second={}".format(*pair)
)
def test_fn(param):
    first, second = param
    assert first != second

Result:

> pytest --verbose 
================================ test session starts =================================
platform linux2 -- Python 2.7.12, pytest-3.6.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python
cachedir: .pytest_cache
rootdir: /home/paulos/work/lixo/tests, inifile:
collected 6 items

test_foo.py::test_fn[first=a, second=b] PASSED                                     [ 16%]
test_foo.py::test_fn[first=a, second=c] PASSED                                     [ 33%]
test_foo.py::test_fn[first=b, second=a] PASSED                                     [ 50%]
test_foo.py::test_fn[first=b, second=c] PASSED                                     [ 66%]
test_foo.py::test_fn[first=c, second=a] PASSED                                     [ 83%]
test_foo.py::test_fn[first=c, second=b] PASSED                                     [100%]

================================ 6 passed in 0.03 seconds ================================

[update]

I think this answer is the solution I will use. Every day is a school day! (Out of curiosity is there a way I could be the 'param' into something like 'first, second' so to have test_foo(param) be test_foo(first, second). I'm not sure that actually helps anything... but I am curious – F. Elliot

If you don't mind a test_fn[a-b] instead of test_fn[a, b]:

@pytest.mark.parametrize(
    'first,second',
    itertools.permutations(OPTIONS, 2),
)
def test_fn(first, second):
    assert first != second

In practice we don't really run tests with --verbose anyway, so most of the time the output will be just a dot for each test.

like image 162
Paulo Scardine Avatar answered Sep 25 '22 00:09

Paulo Scardine