2017-03-29 2 views
2

私は私がテストしたいのですが、以下の機能を持っている:テスト複数コール()

# 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

Pythonでループするために再帰を使用しないでください、 'while'ループを使います。しかし、あなたが再帰呼び出しを使用する場合は、再帰呼び出しが返すものを返さなければなりません: 'return what_year(debug)' – Barmar

+0

whileループに変更すると、pytestループはすべての入力呼び出しでparamsをループしますか?または、return_valueをside_effectに変更し、パラメータを削除し、無効で有効な年のリストを与える必要がありますか? – Ardeezy

+0

申し訳ありませんが、私はpytestについて何も知らない。しかし、単体テストフレームワークに合わせてコードデザインを変更する必要はありません。 – Barmar

答えて

0

なぜ私の質問に対するBarmarのコメントは私のノギングジョギングを得たのか分かりません。

とにかく、質問を閲覧した方の回答です。 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 ===========================