Reputation: 9180
I have a large Python project with many functions that are used by a single driver main.py
. The driver provides the input parameters needed for all the functions. I'm using pytest to test the functions. A basic example of such a project is given below. In the example, parameters are defined as s, t, x, y, z, a, b, c, j, k
.
# main.py
# ----------------------------------------------------------------------------
from funcA import funcA
from funcB import funcB
s = 3.4
t = 8
x = 12.9
y = 51
z = 1.04
a = 456.1
b = 203.09
c = 110.72
j = 2.89
k = 4.5
quantity, average = funcA(s, t, x, y, z)
weight = funcB(a, b, c, j, k, y, z)
print(f'{quantity=}')
print(f'{average=}')
print(f'{weight=}')
# funcA.py
# ----------------------------------------------------------------------------
def funcA(s, t, x, y, z):
quantity = s + t
average = (x + y + z) / 3
return quantity, average
# funcB.py
# ----------------------------------------------------------------------------
def funcB(a, b, c, j, k, y, z):
pounds = a + b + c
kilograms = j + k + y + z
weight = pounds + kilograms
return weight
The tests for the example functions are shown below. The tests are located in a tests
folder which is in the same directory as the main.py
driver.
# test_funcA.py
# ----------------------------------------------------------------------------
import pytest
from funcA import funcA
def test_funcA():
s = 3.4
t = 8
x = 12.9
y = 51
z = 1.04
quantity, average = funcA(s, t, x, y, z)
assert quantity == pytest.approx(11.4)
assert average == pytest.approx(21.64, rel=1e-2)
# test_funcB.py
# ----------------------------------------------------------------------------
import pytest
from funcB import funcB
def test_funcB():
a = 456.1
b = 203.09
c = 110.72
j = 2.89
k = 4.5
y = 51
z = 1.04
weight = funcB(a, b, c, j, k, y, z)
assert weight == pytest.approx(829.34)
For each test, I have to give the input parameters needed for the function being tested. This approach is cumbersome for a large project which has many parameters and functions. So instead of redefining the parameters for each test, I would like to define all the parameters once and pass those parameters to all the tests. How can I do that with pytest?
I defined a fixture in conftest.py
which is located in the tests
folder. This seems to be the pytest way to provide global variables (parameters) to all the tests. The tests use the fixture to get the input parameters for the function.
# conftest.py
# ----------------------------------------------------------------------------
import pytest
from dataclasses import dataclass
@dataclass
class Parameters:
s = 3.4
t = 8
x = 12.9
y = 51
z = 1.04
a = 456.1
b = 203.09
c = 110.72
j = 2.89
k = 4.5
@pytest.fixture()
def parameters():
params = Parameters()
return params
# test_funcA.py
# ----------------------------------------------------------------------------
import pytest
from funcA import funcA
def test_funcA(parameters):
s = parameters.s
t = parameters.t
x = parameters.x
y = parameters.y
z = parameters.z
quantity, average = funcA(s, t, x, y, z)
assert quantity == pytest.approx(11.4)
assert average == pytest.approx(21.64, rel=1e-2)
# test_funcB.py
# ----------------------------------------------------------------------------
import pytest
from funcB import funcB
def test_funcB(parameters):
a = parameters.a
b = parameters.b
c = parameters.c
j = parameters.j
k = parameters.k
y = parameters.y
z = parameters.z
weight = funcB(a, b, c, j, k, y, z)
assert weight == pytest.approx(829.34)
This approach allows me to define the parameter values in one place (in the conftest.py
file). But I still have to declare the input parameter variables in each test so they can be passed to the function that is being tested. Is there another approach where I don't have to redefine the parameters variables for each test? Could I just pass the needed variables to the test (see example below)?
import pytest
from funcA import funcA
def test_funcA(s, t, x, y, z):
quantity, average = funcA(s, t, x, y, z)
assert quantity == pytest.approx(11.4)
assert average == pytest.approx(21.64, rel=1e-2)
Upvotes: 2
Views: 1018
Reputation: 15526
If changes to data must be retained for each subsequent test, then you can pass data between tests using Module-scoped fixtures to solve multiple problems at once.
Here's what that might look like:
import pytest
@pytest.fixture(scope="module")
def data():
a = 11
b = 22
c = 33
d = 44
yield [a, b, c, d]
def test_a(data):
assert data[0] == 11
data[1] = 2222
def test_ab(data):
assert data[0] == 11
assert data[1] == 2222
def test_abc(data):
assert data[0] == 11
assert data[1] == 2222
assert data[2] == 33
data[0] = 1111
def test_abd(data):
assert data[0] == 1111
assert data[1] == 2222
assert data[3] == 44
Notice that the tests are changing data before the next test. Since the tests run alphabetically, they will all pass because the data is changed from the original set. For simplicity, I used a single fixture, but you can use as many fixtures as you'd like.
Copy/paste that into a Python file and try running it with pytest
. It works because the data can be changed and passed between tests.
Part 2 (Based on your code, for what you're looking for.)
import pytest
@pytest.fixture(scope="module")
def s():
value = 3.4
yield value
@pytest.fixture(scope="module")
def t():
value = 8
yield value
@pytest.fixture(scope="module")
def x():
value = 12.9
yield value
@pytest.fixture(scope="module")
def y():
value = 51
yield value
@pytest.fixture(scope="module")
def z():
value = 1.04
yield value
def funcA(s, t, x, y, z):
quantity = s + t
average = (x + y + z) / 3
return quantity, average
def test_funcA(s, t, x, y, z):
quantity, average = funcA(s, t, x, y, z)
assert quantity == pytest.approx(11.4)
assert average == pytest.approx(21.64, rel=1e-2)
Upvotes: 1