我有一個用Python編寫的控制檯程序。它要求使用該命令的用戶的問題:Pytest:如何通過輸入調用來測試函數?
some_input = input('Answer the question:', ...)
我將如何測試中,含有使用pytest
到input
通話功能? 我不想強迫測試人員多次輸入文本來完成一次測試運行。
我有一個用Python編寫的控制檯程序。它要求使用該命令的用戶的問題:Pytest:如何通過輸入調用來測試函數?
some_input = input('Answer the question:', ...)
我將如何測試中,含有使用pytest
到input
通話功能? 我不想強迫測試人員多次輸入文本來完成一次測試運行。
您應該嘲笑內置的input
函數,您可以使用pytest
提供的teardown
功能在每次測試後恢復原始的input
函數。
import module # The module which contains the call to input
class TestClass:
def test_function_1(self):
# Override the Python built-in input method
module.input = lambda: 'some_input'
# Call the function you would like to test (which uses input)
output = module.function()
assert output == 'expected_output'
def test_function_2(self):
module.input = lambda: 'some_other_input'
output = module.function()
assert output == 'another_expected_output'
def teardown_method(self, method):
# This method is being called after each test case, and it will revert input back to original function
module.input = input
更好的解決方案將是爲與with statement
一起使用mock
模塊。這樣你就不需要使用拆卸,修補後的方法只能在with
範圍內生存。
import mock
import module
def test_function():
with mock.patch.object(__builtin__, 'input', lambda: 'some_input'):
assert module.function() == 'expected_output'
正如編譯器建議的,pytest有一個新的monkeypatch夾具。對象可以更改類中的屬性或字典中的值,然後在測試結束時恢復其原始值。
在這種情況下,內置的input
功能是Python __builtins__
字典的價值,所以我們可以改變它,如下所示:
def test_something_that_involves_user_input(monkeypatch):
# monkeypatch the "input" function, so that it returns "Mark".
# This simulates the user entering "Mark" in the terminal:
monkeypatch.setitem('builtins.input', lambda x: "Mark")
# go about using input() like you normally would:
i = input("What is your name?")
assert i == "Mark"
編輯:改變lambda: "Mark"
到lambda x: "Mark"
這應該是'setattr',而不是'setitem'。 – Matt
您可以更換sys.stdin
與一些自定義Text IO,如來自文件或內存中的StringIO緩衝區的輸入:
import sys
class Test:
def test_function(self):
sys.stdin = open("preprogrammed_inputs.txt")
module.call_function()
def setup_method(self):
self.orig_stdin = sys.stdin
def teardown_method(self):
sys.stdin = self.orig_stdin
這比只修補input()
更穩健,因爲如果模塊使用任何其他從標準輸入消耗文本的方法,這將不夠。
這也可以很優雅地完成了一個自定義的上下文管理
import sys
from contextlib import contextmanager
@contextmanager
def replace_stdin(target):
orig = sys.stdin
sys.stdin = target
yield
sys.stdin = orig
,然後只用像這樣的例子:
with replace_stdin(StringIO("some preprogrammed input")):
module.call_function()
可以按如下方式與mock.patch
做到這一點。
首先,在你的代碼,創建調用虛擬函數input
:
def __get_input(text):
return input(text)
在您的測試功能:
import my_module
from mock import patch
@patch('my_module.__get_input', return_value='y'))
def test_what_happens_when_answering_yes(self, mock):
"""
Test what happens when user input is 'y'
"""
# whatever your test function does
例如,如果你已經一個循環檢查的只有有效答案是['y','Y','n','N'],您可以測試在輸入不同的值時沒有任何反應。
在這種情況下,我們假設一個
SystemExit
引發回答「N」時:
@patch('my_module.__get_input')
def test_invalid_answer_remains_in_loop(self, mock):
"""
Test nothing's broken when answer is not ['Y', 'y', 'N', 'n']
"""
with self.assertRaises(SystemExit):
mock.side_effect = ['k', 'l', 'yeah', 'N']
# call to our function asking for input
你去翻關於如何使用'pytest'看你可以嘗試什麼教程?這是一個相當寬泛的問題。 – idjaw
@idjaw不是最近。我之前使用過pytest,但是當考慮在我的項目中爲TDD做TDD時,我想到了這一點,但我不知道如何解決它。我會再看看那些餡餅。 – Zelphir
在您的測試函數中,您可以將'input()'函數重新分配給別的東西(也稱爲「猴子修補」或「陰影」)。 –