我有以下我想测试的功能:
# 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)
如何重写此函数或测试函数以更轻松地测试输入?
答案 0 :(得分:1)
不确定为什么,但Barmar对我的问题的评论得到了我的noggin joggin。
无论如何,对于那些看过这个问题的人来说,这是一个答案。 Per Barmar的评论我也更新了我的功能。
# 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 ===========================