[英]Python3: Testing repeated user input
我在單元測試方面有點初學者,但仍在嘗試熟悉其中的一些內容。 這是我自己項目的一部分,我一直堅持如何全面測試它。
在這個方向上已經有一個問題,但它只關心如何反復詢問用戶輸入,而不是如何對它進行單元測試。
目標:
我有一個 function 要求用戶輸入並在輸入無效時重復請求。 我的目標是弄清楚如果用戶提供無效輸入,如何測試輸入請求是否重復。 我的意思是,我正在嘗試測試在定義的情況下重復輸入請求的機制是否按預期工作。
編碼:
function 向用戶請求一個正則表達式,並將其從重新包(python 標准庫)編譯為 SRE_Pattern object。 如果用戶提供了一個輸入並且它不是一個有效的表達式,那么輸入請求會被重復。
import re
def request_regex_pattern(input_message):
regex_pattern = None
while True:
regex = input(input_message)
if not regex:
print("No Regex provided.")
break
try:
regex_pattern = re.compile(regex, re.IGNORECASE)
break
except re.error:
print("The input was not valid regular expression")
continue
return regex_pattern
到目前為止的測試:
到目前為止,我可以測試的是對於有效輸入(例如\d\d
)我是否使用 ZD1892D85020BA22807BD0D8378206CCZ1 得到正確的 output (該正則表達式的SRE_Pattern
object)。
import unittest as ut
from unittest import mock
import re
class TestUserInput(ut.TestCase):
def test_request_regex_pattern(self):
with mock.patch('builtins.input', return_value='\d\d'):
test_pattern = request_regex_pattern('')
test_string = '01'
self.assertIsNotNone(test_pattern.match(test_string))
我已經考慮過這個問題並在谷歌上搜索了一段時間,但無法得到令人滿意的答案。
有沒有一種明智的方法來測試輸入請求是否被重復? 那里的最佳實踐是什么?
解決方案不強制使用 python 的默認 unittest 庫。 但是,通常會首選使用標准庫的解決方案,因為這會減少我正在處理的項目所需的需求數量。
非常感謝您的寶貴時間 !
BreanBremen 先生為我指出了正確的方向,將我與他的答案聯系起來,並幫助我解決了一些關於語法和理解原理的后續問題。 為了更容易理解,我想詳細說明並簡化他在那里使用的原理。
原則
檢查這一點的方法是修補在您要檢查的情況下調用的 function。 這會將它們替換為 MagicMock 對象,這些對象知道它們何時被調用以及使用哪些參數!
Once the function is patched, you can then use that MagicMocks assert methods such as assert_called_with()
, assert_called_once()
, assert_called()
and/or assert_not_called()
to check whether the function that this MagicMock object replaced was called at all and with the您期望的參數。
現在這如何適用於這個問題?
首先回到我們的問題。 我們有 3 個測試用例:
1) 用戶提供可以編譯成 SRE_Pattern object 的有效正則表達式 --> 返回 SRE_Pattern object
2) 用戶不提供任何輸入(只需按回車鍵)--> 返回無
3) 用戶提供了無法編譯成 SRE_Pattern object 的輸入(無效輸入),觸發print("The input was not valid regular expression")
語句 --> Never Returns nothing
我們只關心 3) 的情況,因為案例 1) 和 2) 有一個定義的 output 我們可以通過“正常”單元測試輕松檢查,而案例 3) 明確不能 output 任何東西,導致我們的問題。
正如 3) 中已經暗示的那樣,在這些情況下,只調用 print function。 這意味着對於我們的測試,我們應該修補它,以便我們可以接收此 function 的 MagicMock 對象,並將其assert_called_with()
與 print-statement 獲取的字符串一起使用,因為該字符串僅出現在該部分代碼中。 在這些情況下它是“獨特的”!
不過,我們還有一個問題要解決。 一旦我們像以前一樣修補了 builtins.input,但是有一些導致我們的 while 循環重復的東西,我們仍然會被困在一個 while 循環中! function 調用request_regex_pattern()
永遠不會結束,由於我們無法正常退出 function ,我們將不得不通過引發Exception
退出。 因此,我們還需要將其修補到當這些情況發生時調用的函數之一。 在這種情況下,我們可以方便地將這種副作用添加到我們的print
補丁中。 然后我們可以使用with self.assertRaises(Exception)
的上下文管理器捕獲該Exception
,以防止我們的測試失敗。
編碼:
import unittest as ut
from unittest import mock
import re
class TestUserInput(ut.TestCase):
def test_request_regex_pattern_non_regex_input(self):
with mock.patch('builtins.input', return_value='\l\d'):
with mock.patch('builtins.print', side_effect=[None, Exception('To Break the Loop!')]) as mocked_print:
with self.assertRaises(Exception):
ui.request_regex_pattern('')
mocked_print.assert_called_with('The input was not valid regular expression')
提高可讀性
這與“通過上下文管理器的補丁”語法保持一致,以與先前顯示的單元測試保持一致。
如您所見,由於所有的上下文管理器,該代碼並不好閱讀。 因此,最好使用補丁裝飾器,就像 MrBreanBremen 所做的那樣,然后將這些函數的 MagicMock 對象作為參數傳遞給您的測試。 按照應用補丁的順序。 這里mocked_input
是修補過的input()
方法的 MagicMock object, mocked_print
是修補過的print()
方法的 MagicMock object。
import unittest as ut
from unittest import mock
import re
class TestUserInput(ut.TestCase):
@mock.patch('builtins.input', return_value='\l\d')
@mock.patch('builtins.print', side_effect=[None, Exception('To Break the Loop!')])
def test_request_regex_pattern_non_regex_input(self, mocked_input, mocked_print):
with self.assertRaises(Exception):
request_regex_pattern('')
mocked_print.assert_called_with('The input was not valid regular expression')
防止用戶多次輸入相同輸入的可靠方法是簡單地使用 python 內置列表。 您可以使用預先確定的大小並在其中存儲那么多元素。 您可以將 append 元素添加到列表中,然后如果超出預定大小,則從前面彈出元素(最舊的元素)。 這樣,您就可以確保用戶無法輸入與最后 N 個(列表大小)輸入相同的輸入。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.