在单元测试方面,我是一个初学者,并且仍然试图熟悉其中的一些事情。这是我自己项目的一部分,我一直在研究如何对它进行全面测试。
在这个方向上已经有了一个问题,但它只关心如何反复要求用户输入,而不是如何对其进行统一测试。
目标:
我有一个函数,它要求用户输入并在输入无效时重复请求。我的目标是找出如何测试输入请求是否重复,如果用户提供无效的输入。我的意思是,我试图测试在定义的情况下重复输入请求的机制是否正常工作。
代码:
该函数向用户请求一个正则表达式,并将其编译为regular中的SRE_Pattern对象(python库)。如果用户提供了一个输入,并且它不是一个有效的表达式,则输入请求将被重复。
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),是否使用模拟获得正确的输出(该正则表达式的SRE_Pattern对象)。
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库并不是必需的。但是,使用标准库的解决方案通常是首选的,因为这样可以减少我正在处理的项目所需的需求数量。
非常感谢您的时间!
发布于 2020-05-21 18:29:56
MrBreanBremen为我指出了正确的方向,将我与他的答案联系起来,并善意地帮助我回答了一些关于语法和理解原则的后续问题。为了更容易理解,我想详细阐述一下他在那里使用的原则。
原理
检查这一点的方法是修补在要检查的情况下调用的函数。这将替换为MagicMock对象,这些对象知道何时调用了它们,以及使用了哪些参数!
一旦对函数进行了修补,就可以使用MagicMocks断言方法(如assert_called_with()、assert_called_once()、assert_called()和/或assert_not_called() )来检查是否调用了这个MagicMock对象所替换的函数,并且使用了您所期望的参数。
,现在这如何适用于这个问题?
首先回到我们的问题。我们有三个测试案例:
1)用户提供可编译为SRE_Pattern对象的有效正则表达式-->返回SRE_Pattern对象
2)用户不提供任何输入(只点击enter) ->不返回任何
3)用户提供无法编译成SRE_Pattern对象的输入(无效输入),触发print("The input was not valid regular expression")语句->从不返回任何内容
我们只关心情况,如例1)和( 2)有一个定义的输出,我们可以很容易地检查“正常”单元测试,而案例3)明确不能输出任何东西,导致我们的问题。
如前所述,在这种情况下,只有打印函数才会被调用。这意味着对于我们的测试,我们应该修补它,这样我们就可以为这个函数接收一个MagicMock对象,并使用它的assert_called_with()和print-语句获取的字符串,因为该字符串只发生在代码的那一部分中。对于这些情况,它是“独一无二的”!
不过,我们还有一个问题要解决。一旦我们像以前一样修补了builtins.input,但是有了什么东西会导致我们的while循环重复,我们仍然会陷入一个时间循环中!函数调用request_regex_pattern()永远不会结束!由于不能正常退出函数,因此必须通过引发Exception来退出。因此,当这些情况发生时,我们还需要将其修补为调用的函数之一。在这种情况下,我们可以方便地将这种副作用添加到我们的print补丁中。然后,我们可以使用上下文管理器Exception捕获该with self.assertRaises(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')改进可读性
为了与先前显示的单元测试保持一致,“通过上下文管理器的修补程序”-syntax也保留了这一点。
正如您所看到的,由于所有的上下文管理器,这些代码读起来不太好。因此,最好像MrBreanBremen那样使用修补程序装饰器!然后,按照应用补丁的顺序,将这些函数的MagicMock对象作为参数传递给您的测试。这里,mocked_input是修补的input()方法的MagicMock对象,mocked_print是修补的print()方法的MagicMock对象。
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')发布于 2020-05-21 16:23:44
防止用户多次输入相同输入的一个可靠方法是简单地使用python内置列表。您可以使用预先确定的大小,只需将许多元素存储在其中。您可以将元素追加到列表中,如果预先确定的大小超过了前面的pop元素(最老的元素)。这样,您就可以确保用户不能输入与最后一个N(列表的大小)输入相同的输入。
https://stackoverflow.com/questions/61938836
复制相似问题