Запустите настройку для выбранных комбинаций параметров в pytest - PullRequest
0 голосов
/ 11 марта 2019

В одном из моих тестов проекта у меня есть функция, которую нужно протестировать с большим пространством параметров. Эта функция имеет большие издержки и, кроме того, вычисление для каждого набора параметров занимает довольно много времени. Таким образом, полезно выполнить расчет со всеми параметрами одновременно, а затем использовать результаты в отдельных тестах. Также я ввел маркер, который позволяет мне выбирать разные наборы параметров. Один набор параметров используется во время разработки, в то время как другой набор параметров работает в течение ночи. Теперь в этом конкретном проекте есть еще несколько маркеров, и люди используют их для разных целей. Таким образом, я хотел бы получить доступ к выбранным наборам параметров в своем установочном приспособлении, чтобы предоставить результаты для всех наборов параметров, которые были протестированы в конкретном прогоне.

Ниже приведен минимальный пример теста:

import pytest
import time


class Parametrization(object):
    PARAM_A = [0, 1, 2, 3, 4]
    PARAM_B = [10, 20, 30, 40, 50, 60]
    NAMES = "param_a,param_b"

    QUICK_PARAM_SPACE = [
        (0, 20),
        (4, 50)]

    def parameter_list(self):
        return [
            (param_a, param_b)
            for param_a in self.PARAM_A
            for param_b in self.PARAM_B]

    @staticmethod
    def param_id(param_a, param_b):
        return "A_{param_a}_B_{param_b}".format(
            param_a=param_a, param_b=param_b)

    @property
    def pytest_param_decorator(self):
        parameters = []
        for (param_a, param_b) in self.parameter_list():
            if (param_a, param_b) in self.QUICK_PARAM_SPACE:
                parameters.append(pytest.param(
                    param_a, param_b,
                    id=self.param_id(param_a, param_b)))
            else:
                parameters.append(pytest.param(
                    param_a, param_b,
                    id=self.param_id(param_a, param_b),
                    marks=pytest.mark.extended_parameter_set))

        return pytest.mark.parametrize(self.NAMES, parameters)


PARAM = Parametrization()


@pytest.fixture(scope="module")
def job_result():
    """
    This function runs some calculation that is expensive for each parameter
    set but also has some overhead, so it's much cheaper to run it with all
    parameter sets at once than running it for each parameter set individually.
    """

    print("Simulated overhead")
    time.sleep(1)

    result = {}
    for param_a, param_b in PARAM.parameter_list():
        print("Calculate parameter combination {} - {}.".format(
            param_a, param_b))
        time.sleep(0.1)
        result[(param_a, param_b)] = param_a + param_b

    yield result


@PARAM.pytest_param_decorator
def test_example(job_result, param_a, param_b):
    assert job_result[param_a, param_b] == param_a + param_b

Запуск этого теста с использованием

py.test test_example.py -s -m "not extended_parameter_set"

будет правильно запускать «test_example» только комбинации параметров «A_0_B_20» и «A_4_B_50». Тем не менее, он все равно вычислит все другие комбинации параметров в "job_result". Мне нужно получить доступ к выбранным комбинациям параметров в функции "job_result", чтобы я мог выполнять вычисления только для выбранных комбинаций параметров. Есть ли хороший способ добиться этого?

1 Ответ

0 голосов
/ 15 марта 2019

На самом деле это может быть достигнуто довольно легко с помощью фиксатора запроса.При этом можно просто зациклить запрошенные элементы и получить оттуда параметры:

for item in request.session.items:
    if item.get_marker("skip") is not None:
        continue
    param_a = item.callspec.getparam("param_a")
    param_b = item.callspec.getparam("param_b")
    ...

Полный пример выглядит так:

import pytest
import time


class Parametrization(object):
    PARAM_A = [0, 1, 2, 3, 4]
    PARAM_B = [10, 20, 30, 40, 50, 60]
    NAMES = "param_a,param_b"

    QUICK_PARAM_SPACE = [
        (0, 20),
        (4, 50)]

    def parameter_list(self):
        return [
            (param_a, param_b)
            for param_a in self.PARAM_A
            for param_b in self.PARAM_B]

    @staticmethod
    def param_id(param_a, param_b):
        return "A_{param_a}_B_{param_b}".format(
            param_a=param_a, param_b=param_b)

    @property
    def pytest_param_decorator(self):
        parameters = []
        for (param_a, param_b) in self.parameter_list():
            if (param_a, param_b) in self.QUICK_PARAM_SPACE:
                parameters.append(pytest.param(
                    param_a, param_b,
                    id=self.param_id(param_a, param_b)))
            else:
                parameters.append(pytest.param(
                    param_a, param_b,
                    id=self.param_id(param_a, param_b),
                    marks=pytest.mark.extended_parameter_set))

        return pytest.mark.parametrize(self.NAMES, parameters)


PARAM = Parametrization()


@pytest.fixture(scope="module")
def job_result(request):
    """
    This function runs some calculation that is expensive for each parameter
    set but also has some overhead, so it's much cheaper to run it with all
    parameter sets at once than running it for each parameter set individually.
    """

    print("Simulated overhead")
    time.sleep(1)

    result = {}
    for item in request.session.items:
        if item.get_marker("skip") is not None:
            continue
        param_a = item.callspec.getparam('param_a')
        param_b = item.callspec.getparam('param_b')
        print("Calculate parameter combination {} - {}.".format(
            param_a, param_b))
        time.sleep(0.1)
        result[(param_a, param_b)] = param_a + param_b

    yield result


@PARAM.pytest_param_decorator
def test_example(job_result, param_a, param_b):
    assert job_result[param_a, param_b] == param_a + param_b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...