测试多个调用输入()

时间:2017-03-29 07:34:43

标签: python unit-testing

我有以下我想测试的功能:

# Ask user input, returns year
def what_year():
    # Get the first input from the user.
    year = input('\n\tEnter the year you would like to START your range: \n\t')

    # Catch the error if the user doesn't enter a convertable string.
    try:
        year = int(year)
    except ValueError:
        print(error_msg.format(year))
        what_year()

    # We only want years between 2005 and today's year.
    if year not in range(2005, int(datetime.now().year +1)):
        print(error_msg.format(year))
        what_year()

    return year

我想测试它而不必引发任何错误,因为理想情况下,在用户输入可接受的输入之前,函数会连续循环而不会引发错误。

我迷失了如何让pytest循环输入。我试图用mock修补builtins.input,并且它可以为我的函数提供指定的输入,但理想情况下,测试将能够成功遍历输入列表。

例如,从我下面的测试代码开始,在现实世界中,用户首先会查看所有无效选项,然后最终开始输入有效选项,函数最终会开始返回“year”。

我通过为每个函数创建一个调试参数来粗略解决这个问题,然后在出于测试目的打开调试时引发一个值错误,但这似乎很简陋:

功能:

# Ask user input, returns year
def what_year(debug=False):
    # Get the first input from the user.
    year = input('\n\tEnter the year you would like to START your range: \n\t')

    # Catch the error if the user doesn't enter a convertable string.
    try:
        year = int(year)
    except ValueError:

        # Only raise ValueError if debug is on for testing purposes.
        if debug:
            raise ValueError

        print(error_msg.format(year))
        what_year(debug)

    # We only want years between 2005 and today's year.
    if year not in range(2005, int(datetime.now().year +1)):

        if debug:
            raise ValueError

        print(error_msg.format(year))
        what_year(debug)

    return year

测试:

import mock
import pytest
from redditimagescraper import RedditImageScraper

@pytest.mark.parametrize('invalid_years', ["9999", "0", "", " ", "-2015"])
def test_what_year_invalid(invalid_years):
    # Test invalid years
    with pytest.raises(ValueError):
        with mock.patch('builtins.input', return_value=invalid_years):
            RedditImageScraper.what_year(True)


@pytest.mark.parametrize('valid_years', [str(year) for year in range(2005,2018)])
def test_what_year_valid(valid_years):
    # Test valid years
    with mock.patch('builtins.input', return_value=valid_years):
        assert RedditImageScraper.what_year(True) == int(valid_years)

如何重写此函数或测试函数以更轻松地测试输入?

1 个答案:

答案 0 :(得分:1)

不确定为什么,但Barmar对我的问题的评论得到了我的noggin joggin。

无论如何,对于那些看过这个问题的人来说,这是一个答案。 Per Barmar的评论我也更新了我的功能。

what_year()函数:

# Ask user input, returns year
def what_year(start_or_end):
    while True:
        try:
            # Catch the error if the user doesn't enter a convertable string.
            # Get input from the user.
            year = int(input('\n\tEnter the year you would like to {} your range: '.format(start_or_end)))

            # We only want years between 2005 and today's year.
            if year in range(2005, int(datetime.now().year + 1)):
                # Success!
                break
            else:
                print(error_msg.format(year))
        except:
            print(error_msg.format('ValueError'))
            pass

    return year

测试功能:

# Parametrize my valid answers
@pytest.mark.parametrize('valid_year', [str(year) for year in range(2005, datetime.now().year + 1)])
def test_what_year(valid_year):

    # years = a bunch of invalid inputs with a valid input at the end
    years = ["9999", "0", "", " ", "-2015", "-30", str(10^1000), valid_year]

    # side_effect, when given an iterable, iterates through
    # each time the patched function is called (in this case input())
    with mock.patch('builtins.input', side_effect=years):
        assert RedditImageScraper.what_year('start') == int(valid_year)

运行pytest -v给了我这个:

============================= test session starts ==============================
platform linux -- Python 3.6.0, pytest-3.0.7, py-1.4.33, pluggy-0.4.0 -- /home/ardeaf/Projects/RedditImageScraper/venv/bin/python3
cachedir: .cache
rootdir: /home/ardeaf/Projects/RedditImageScraper, inifile: setup.cfg
collecting ... collected 12 items

tests/RedditImageScraper_test.py::test_what_year[2005] PASSED
tests/RedditImageScraper_test.py::test_what_year[2006] PASSED
tests/RedditImageScraper_test.py::test_what_year[2007] PASSED
tests/RedditImageScraper_test.py::test_what_year[2008] PASSED
tests/RedditImageScraper_test.py::test_what_year[2009] PASSED
tests/RedditImageScraper_test.py::test_what_year[2010] PASSED
tests/RedditImageScraper_test.py::test_what_year[2011] PASSED
tests/RedditImageScraper_test.py::test_what_year[2012] PASSED
tests/RedditImageScraper_test.py::test_what_year[2013] PASSED
tests/RedditImageScraper_test.py::test_what_year[2014] PASSED
tests/RedditImageScraper_test.py::test_what_year[2015] PASSED
tests/RedditImageScraper_test.py::test_what_year[2016] PASSED
tests/RedditImageScraper_test.py::test_what_year[2017] PASSED

========================== 12 passed in 0.31 seconds ===========================