Как подчеркнуть ограничения для входных данных в модульном тестировании?

У меня есть параметризованный тест, например:

import pytest
from datetime import time


def get_next_hour(time_str: str):
    t = time(*map(int, time_str.split(':')))
    new_t = time((t.hour + 1) % 24, t.minute)
    return new_t.strftime('%H:%M')


@pytest.mark.parametrize(
    "t_str, result_str",
    [
        ('10:30', '11:30'),
        ('11:30', '12:30'),
    ]
)
def test_good_input(t_str, result_str):    
    result = get_next_hour(t_str)
    assert result == result_str

Тест test_good_input должен работать только с допустимыми строками времени (для некорректных данных у меня есть другой тест test_bad_input). Как я могу это подчеркнуть - в строке документации или используя утверждение для входных данных?

Со строкой документации

def test_good_input(t_str, result_str):
    """for t_str allowed only time-valid strings"""

    result = get_next_hour(t_str)
    assert result == result_str

С проверочным вводом

def test_good_input(t_str, result_str):

    assert ':' in t_str, 'input data is not time'

    result = get_next_hour(t_str)
    assert result == result_str

Или есть другие способы?

Разве вы уже не подчеркиваете это, указывая аргументы в mark.parametrize?

hoefling 08.02.2019 18:37

@hoefling Да, я так и делаю, но если другой разработчик (или я через несколько месяцев) добавит новые параметризованные аргументы, я хотел бы напомнить, какими они должны быть.

Анатолий Панин 10.02.2019 11:20
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
50
2

Ответы 2

Я бы сказал, что толстого предупреждения в комментарии или строки документации тестовой функции должно быть достаточно. Это не ненадежный пользовательский ввод, который следует проверить; Кроме того, лучше, чтобы тесты были как можно более простыми. Если какой-то разработчик неправильно использует тестовые входные данные, не прочитав сначала документы, теперь это его собственная вина.

Тем не менее, проверка тестовых аргументов, безусловно, возможна с pytest (например, чтобы сообщить разработчикам, что с тестируемой функцией все в порядке, и они используют тест неправильно). Я бы сделал неявную проверку аргументов, используя косвенную параметризацию. В приведенном ниже примере каждый аргумент из mark.parametrize будет сначала передан фикстуре с тем же именем, где вы сможете выполнить предварительную обработку перед началом теста:

def validate(input):
    try:
        datetime.strptime(input, '%H:%M')
    except ValueError as e:
        pytest.fail('Your test parametrization is wrong. The test argument is erroneous: {}'.format(e))


@pytest.fixture
def t_str(request):
    validate(request.param)
    return request.param


@pytest.fixture
def result_str(request):
    validate(request.param)
    return request.param


@pytest.mark.parametrize(
    "t_str, result_str",
    [
        ('10:30', '11:30'),
        ('11:30', '12:30'),
        ('10:30', 'bar'),
    ],
    indirect=True
)
def test_good_input(t_str, result_str):
    ...

Теперь третий тест завершится ошибкой с описательным сообщением об ошибке:

test_spam.py::test_good_input[10:30-11:30] PASSED
test_spam.py::test_good_input[11:30-12:30] PASSED
test_spam.py::test_good_input[10:30-bar] ERROR

============================================= ERRORS ==============================================
__________________________ ERROR at setup of test_good_input[10:30-bar] ___________________________

...

input = 'bar'

    def validate(input):
        try:
            datetime.strptime(input, '%H:%M')
        except ValueError as e:
>           pytest.fail('Your test parametrization is wrong. The test argument is erroneous: {}'.format(e))
E           Failed: Your test parametrization is wrong. The test argument is erroneous: time data 'bar' does not match format '%H:%M'

test_spam.py:15: Failed
================================ 2 passed, 1 error in 0.05 seconds ================================

Дополнительная информация о косвенной параметризации: Откладывание настройки параметризованных ресурсов

Вы, конечно, можете добавить дополнительные комментарии или тому подобное. Но у вас уже есть некоторые естественные места для выражения ваших намерений: вашей тестовой функции можно дать более описательное имя, чем test_good_input, аргументам вашей тестовой функции можно дать более описательные имена, а переменные, вспомогательные функции и т. д. — все они могут иметь описательные имена. имена.

Например, вы можете назвать свою тестовую функцию test_getNextHour_withValidTimeString_shouldGiveOneHourLaterTimeString. Я бы сказал, что этим все сказано. Если вы переименуете t_str в valid_time_str или что-то подобное, это дополнительно передает сообщение также в верхней части поля параметра.

Я бы не стал добавлять утверждения или что-то еще - ввод недопустимой строки времени в качестве входных данных в любом случае приведет к неудачному тестовому случаю.

Другие вопросы по теме