如何强调单元测试中输入数据的限制?

问题描述 投票:1回答:2

我有参数化测试,例如:

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)。我如何强调它 - 在docstring中,或者使用assert输入数据?

使用docstring

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

还是有其他方法?

python unit-testing pytest design-by-contract
2个回答
1
投票

我会在评论或测试函数docstring中说一个胖警告就足够了。这不是应该验证的不可信用户输入;另外,最好让测试尽可能简单。如果某些开发人员在没有首先阅读文档的情况下滥用测试输入,那么现在就是他自己的错。

但是,使用pytest肯定可以进行测试args验证(例如,告知开发人员测试函数没有任何问题,并且他们使用的测试错误)。我会使用间接参数化进行隐式args验证。在下面的示例中,来自mark.parametrize的每个arg将首先传递到具有相同名称的fixture,您可以在测试开始之前进行预处理:

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 ================================

有关间接参数化的更多信息:Deferring the setup of parametrized resources


0
投票

你当然可以添加额外的评论等。但是,您已经有了一些自然的地方来表达您的意图:您的测试函数可以被赋予比test_good_input更具描述性的名称,您的测试函数的参数可以被赋予更多的描述性名称,变量,辅助函数等都可以具有描述性名。

例如,您可以将测试函数命名为test_getNextHour_withValidTimeString_shouldGiveOneHourLaterTimeString。我认为这说明了一切。如果将t_str重命名为valid_time_str或类似的东西,这还会在参数字段的顶部传达消息。

我不会添加断言或其他 - 给出无效的时间字符串作为输入将导致失败的测试用例无论如何。

© www.soinside.com 2019 - 2024. All rights reserved.