如何使用 pytest 函数对每个站点使用不同的测试数据集来测试不同的站点,例如 staging/production

how to use a pytest function to test different site using a different set of test data for each site such as staging/production

我有一组 pytest 函数来测试 API,测试数据在 json 文件中,由 pytest.mark.parametrize 加载。因为staging、production和pre_production的数据不同但相似,所以我想把测试数据保存在不同的文件夹中并使用相同的文件名,以保持python函数的干净。站点信息是 pytest 命令行的一个新选项。不行,pytest.mark.parametrize 无法获取正确的文件夹来收集测试数据。

这是在conftest.py

@pytest.fixture(autouse=True)
def setup(request, site):
    request.cls.site = site
    yield

def pytest_addoption(parser):
    parser.addoption("--site", action="store", default="staging")

@pytest.fixture(scope="session", autouse=True)
def site(request):
    return request.config.getoption("--site")

这在测试用例文件中:

@pytest.mark.usefixtures("setup")
class TestAAA:

    @pytest.fixture(autouse=True)
    def class_setup(self):
        self.endpoint = read_data_from_file("endpoint.json")["AAA"][self.site]

        if self.site == "production":
            self.test_data_folder = "SourcesV2/production/"
        else:  // staging
            self.test_data_folder = "SourcesV2/"

        testdata.set_data_folder(self.test_data_folder)

    @pytest.mark.parametrize("test_data", testdata.read_data_from_json_file(r"get_source_information.json"))
    def test_get_source_information(self, test_data):
        request_url = self.endpoint + f"/AAA/sources/{test_data['sourceID']}"
        response = requests.get(request_url)
        print(response)

我可以使用 pytest.skip 跳过不适用于当前站点的测试数据。

if test_data["site"] != self.site:
    pytest.skip("this test case is for " + test_data["site"] + ", skiping...")

但是staging/production/pre-production需要把所有的测试数据放在一个文件里,而且报告中会有很多跳过的测试,这不是我喜欢的。

你有什么办法解决这个问题吗?如何根据站点将不同的文件名传递给参数化? 或者,至少,如何让跳过的测试不在报告中写入日志? 谢谢

parametrize 装饰器在加载时计算,而不是在 运行 时计算,因此您不能直接为此使用它。您需要在 运行 时间进行参数化。这可以使用 pytest_generate_tests 钩子来完成:

def pytest_generate_tests(metafunc):
    if "test_data" in metafunc.fixturenames:
        site = metafunc.config.getoption("--site")
        if site == "production":
            test_data_folder = "SourcesV2/production"
        else:
            test_data_folder = "SourcesV2"
        # this is just for illustration, your test data may be loaded differently 
        with open(os.path.join(test_data_folder, "test_data.json")) as f:
            test_data = json.load(f)
        metafunc.parametrize("test_data", test_data)

class TestAAA:

    def test_get_source_information(self, test_data):
        ...

如果加载测试数据是膨胀的,您也可以缓存它以避免每次测试都读取它。