Параметризация внутри класса - PullRequest
0 голосов
/ 05 августа 2020

Допустим, у меня есть функция, которая принимает строку и возвращает первые 5 символов:

def crop_string(x):
    return x[0:5]

Например:

>>> print(crop_string("hello world"))
hello

Теперь скажем, я хочу протестировать эту функцию . Содержимое тестового модуля может быть следующим:

baseline = "hello"
longer = "hello world"
even_longer = "hello world!"

@pytest.mark.parametrize(
    "input_string, expected_result",
    [
        (baseline, baseline),
        (longer, baseline),
        (even_longer, baseline),
    ],
)
def test_crop_string(input_string, expected_result):
    assert crop_string(input_string) == expected_result

Что будет нормально работать.

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

class TestCropString:

    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"

    @pytest.mark.parametrize(
        "input_string, expected_result",
        [
            (baseline, baseline),
            (longer, baseline),
            (even_longer, baseline),
        ],
    )
    def test_crop_string(input_string, expected_result):
        assert crop_string(input_string) == expected_result

Это дает мне ошибку: In test_crop_string: function uses no argument 'input_string'.

Итак, у меня 2 вопросы:

  1. Каков «хороший» способ «передать» параметры теста (baseline, longer, even_longer) для запуска тестов.
  2. Будет ли какая-то польза от определения этих тестовых параметров внутри прибора, например, следующим образом?
@pytest.fixture
def setup_test_data():
    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"

    return baseline, longer, even_longer

(Это был немного глупый пример, но, надеюсь, его достаточно, чтобы объяснить мои вопрос).

Спасибо!

1 Ответ

1 голос
/ 05 августа 2020

Поскольку декораторы оцениваются во время загрузки, вы не можете использовать там переменные класса, поскольку класс неизвестен во время загрузки. Это означает, что вы должны определять свои параметры либо внутри класса, либо вне класса.

Часто делается определение параметров в глобальной функции:

def get_params():
    baseline = "hello"
    longer = "hello world"
    even_longer = "hello world!"
    return [
        (baseline, baseline),
        (longer, baseline),
        (even_longer, baseline)
    ]

...
    @pytest.mark.parametrize("input_string, expected_result", get_params())
    def test_crop_string(self, test_data):
        ...

Это позволяет избежать, по крайней мере, использования глобальных переменных в этом случае.

Что касается декоратора: вы также не можете использовать фикстуру внутри декоратора. Вы можете использовать параметризованный прибор, но это имеет смысл только в том случае, если вы хотите использовать одни и те же параметры в нескольких тестовых методах своего класса:

@pytest.fixture(params=get_params())
def test_data(request):
    return request.param
 
class class TestCropString:

    def test_crop_string(self, test_data):
        assert crop_string(test_data[0]) == test_data[1]

Если вы хотите применить одни и те же параметры ко всем тестовым методам в вместо этого класса вы можете поместить в класс декоратор mark.paramtrize.

@pytest.mark.parametrize("input_string, expected_result", get_params())
class TestCropString:

    def test_crop_string(input_string, expected_result):
        assert crop_string(input_string) == expected_result
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...