问题: 假设一个流程需要 10 个步骤才能完成。我一一开始该过程的步骤,在这些步骤之间,我想做出不同的断言。每次断言后,我都会继续执行其余步骤。 我希望每个断言都作为测试用例发生。所以如果有 5 个断言,我需要 5 个测试用例。如果有 2 组参数化值,那么我需要每组进行 5 次断言,因此将执行 10 个测试用例。我可以将所有步骤放在一个测试用例本身中,但我特别希望断言是单独的测试用例。
以下是我的代码。
# conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--data", action="store", default="1,2 3,4 5,6", help="Data for parametrization")
def pytest_generate_tests(metafunc):
data_str = metafunc.config.getoption("data")
# data_list = [(1, 2), (3, 4), (5, 6)]
data_list = [tuple(map(int, item.split(','))) for item in data_str.split()]
metafunc.parametrize("arithmetic_data", data_list, indirect=True)
@pytest.fixture(scope="function")
def arithmetic_data(request):
return request.param
# test_allure.py
import pytest
class TestClass:
@pytest.fixture
def arithmetic_data(self, arithmetic_data):
self.a, self.b = arithmetic_data # Step 1
self.a, self.b = self.a * 2, self.b * 3
self.c, self.d = self.a * 10, self.b * 10 # Step 4
def test_addition(self, arithmetic_data): # Step 2
result = self.a + self.b
assert result == self.a + self.b, f"Addition failed: {self.a} + {self.b} != {result}"
def test_subtraction(self, arithmetic_data): # Step 3
result = self.a - self.b
assert result == self.a - self.b, f"Subtraction failed: {self.a} - {self.b} != {result}"
def test_multiplication(self, arithmetic_data): # Step 5
result = self.c * self.d
assert result == self.c * self.d, f"Multiplication failed: {self.c} * {self.d} != {result}"
def test_square(self, arithmetic_data): # Step 6
result = self.a * self.a
assert result == self.a * self.a, f"Square failed: {self.a}^2 != {result}"
我认为我做了什么:
我将参数化值放入一个类中,在
arithmetic_data
函数中进行了一些后处理(步骤 1)。我将此函数作为参数传递给第一个测试用例(
test_addition
- 步骤 2),然后执行第二个测试用例(
test_subtraction
- 步骤 3)。
在这个地方,我想执行步骤 4,为什么是因为这里生成的一些值需要传递给其余的测试。然后我将这些值传递给
test_multiplication
(步骤 5)。然后,我执行下一步,即最后一个测试用例。
我知道这很糟糕,因为我无法并行运行它,因为这些步骤必须按顺序执行。但理想情况下,我希望每个进程对于每个参数化值集并行运行。任何有关解决此问题的指示都会非常有帮助。谢谢。
你遇到的问题是,你试图在一个本质上是顺序的流程中强制执行测试用例的并行性。你希望在多个测试用例中对同一组数据执行一系列步骤,这与 pytest 的设计理念相悖,pytest 的设计理念是将测试用例相互隔离。
为了解决这个问题,你需要重新考虑你的测试结构。与其尝试在多个测试用例中对同一组数据执行一系列步骤,不如将每个“步骤”视为一个独立的测试用例,每个测试用例都执行必要的设置和断言。
以下是如何重构代码以实现此目的的方法:
# conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--data", action="store", default="1,2 3,4 5,6", help="Data for parametrization")
def pytest_generate_tests(metafunc):
data_str = metafunc.config.getoption("data")
data_list = [tuple(map(int, item.split(','))) for item in data_str.split()]
metafunc.parametrize("a, b", data_list)
# test_allure.py
import pytest
class TestClass:
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4), (5, 6)])
def test_step1_and_2(self, a, b): # Step 1 & 2
a, b = a * 2, b * 3 # Step 1
result = a + b # Step 2
assert result == a + b, f"Addition failed: {a} + {b} != {result}"
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4), (5, 6)])
def test_step3(self, a, b): # Step 3
a, b = a * 2, b * 3
result = a - b
assert result == a - b, f"Subtraction failed: {a} - {b} != {result}"
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4), (5, 6)])
def test_step4_5(self, a, b): # Step 4 & 5
a, b = a * 2, b * 3
c, d = a * 10, b * 10 # Step 4
result = c * d # Step 5
assert result == c * d, f"Multiplication failed: {c} * {d} != {result}"
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4), (5, 6)])
def test_step6(self, a, b): # Step 6
a, b = a * 2, b * 3
result = a * a
assert result == a * a, f"Square failed: {a}^2 != {result}"
在这个重构的版本中:
- 每个测试用例都代表流程中的一个“步骤”。
-
每个测试用例都接收参数化数据
a
和b
。 -
每个测试用例都执行必要的设置(例如,计算
c
和d
)并在其特定步骤的结果上进行断言。
这种方法使的测试用例相互独立,允许并行执行,并使的测试套件更易于理解和维护。
标签:python,python-3.x,pytest,hook,command-line-arguments From: 78773786