正确 'continue' 行为的单元测试
Unittesting for correct 'continue' behaviour
我有一个通过提示要求用户确认的功能。它接受 y 或 n 作为答案,否则它会再次询问。
现在,我想为这个函数写一个单元测试。我可以很好地测试 y 或 n 的正确行为,但是 我如何测试我的函数是否正确拒绝不可接受的输入?
这是 foo.py
的代码:
def get_input(text):
"""gets console input and returns it; needed for mocking during unittest
"""
return input(text)
def confirm(message='Confirm?', default=False):
"""prompts for yes or no response from the user. Returns True for yes and
False for no.
'default' should be set to the default value assumed by the caller when
user simply types ENTER, and is marked in the prompt with square brackets.
"""
if default:
message = '%s [y]|n: ' % (message) # default answer = yes
else:
message = '%s y|[n]: ' % (message) # default answer = no
while True:
answer = get_input(message).lower()
if not answer:
return default
if answer not in ['y', 'n']:
print('Please enter y or n!')
continue
if answer == "y":
return True
if answer == 'n':
return False
answer = confirm()
print(answer)
这是我的测试 class:
import unittest
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
@unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
那么,如何为“1”之类的输入值编写类似的测试(或者我需要如何调整 confirm() 函数以使其可测试)?
目前,如果我从 unittest 文件中调用 foo.confirm()
,它只会陷入无限循环,而不会 return 任何东西。 (我明白为什么会这样,只是不知道如何规避它。)
有什么想法吗?
你可以试试这个:
import unittest, unittest.mock
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
@unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
@unittest.mock.patch('builtins.print')
@unittest.mock.patch('foo.get_input', side_effect=['1','yn','yes','y']) # this will make the mock return '1', 'yn' and so on in sequence
def test_invalid_answer(self, mock_input, mock_print):
self.assertEqual(foo.confirm(), True) # it should eventually return True
self.assertEqual(mock_input.call_count, 4) # input should be called four times
mock_print.assert_called_with('Please enter y or n!')
在第二个测试用例中,我们模拟一个用户输入了三个无效输入,在再次提示后,最终输入了'y'。所以我们修补 foo.get_input
的方式是 returns 1
第一次被调用,然后是 yn
,然后是 yes
,最后是 y
.前三个示例应该使确认功能再次提示用户。我还修补了打印功能,以便 'Please enter y or n!' 消息在测试时不会出现。这不是必需的。
然后我们断言我们的模拟输入被调用了四次,这意味着前三次,确认函数被重新提示。
最后我们断言打印函数被调用(至少一次)'Please enter y or n!'。
这不会测试打印语句的数量是否正确或它们的顺序是否正确,但我怀疑这也是可能的
我有一个通过提示要求用户确认的功能。它接受 y 或 n 作为答案,否则它会再次询问。
现在,我想为这个函数写一个单元测试。我可以很好地测试 y 或 n 的正确行为,但是 我如何测试我的函数是否正确拒绝不可接受的输入?
这是 foo.py
的代码:
def get_input(text):
"""gets console input and returns it; needed for mocking during unittest
"""
return input(text)
def confirm(message='Confirm?', default=False):
"""prompts for yes or no response from the user. Returns True for yes and
False for no.
'default' should be set to the default value assumed by the caller when
user simply types ENTER, and is marked in the prompt with square brackets.
"""
if default:
message = '%s [y]|n: ' % (message) # default answer = yes
else:
message = '%s y|[n]: ' % (message) # default answer = no
while True:
answer = get_input(message).lower()
if not answer:
return default
if answer not in ['y', 'n']:
print('Please enter y or n!')
continue
if answer == "y":
return True
if answer == 'n':
return False
answer = confirm()
print(answer)
这是我的测试 class:
import unittest
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
@unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
那么,如何为“1”之类的输入值编写类似的测试(或者我需要如何调整 confirm() 函数以使其可测试)?
目前,如果我从 unittest 文件中调用 foo.confirm()
,它只会陷入无限循环,而不会 return 任何东西。 (我明白为什么会这样,只是不知道如何规避它。)
有什么想法吗?
你可以试试这个:
import unittest, unittest.mock
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
@unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
@unittest.mock.patch('builtins.print')
@unittest.mock.patch('foo.get_input', side_effect=['1','yn','yes','y']) # this will make the mock return '1', 'yn' and so on in sequence
def test_invalid_answer(self, mock_input, mock_print):
self.assertEqual(foo.confirm(), True) # it should eventually return True
self.assertEqual(mock_input.call_count, 4) # input should be called four times
mock_print.assert_called_with('Please enter y or n!')
在第二个测试用例中,我们模拟一个用户输入了三个无效输入,在再次提示后,最终输入了'y'。所以我们修补 foo.get_input
的方式是 returns 1
第一次被调用,然后是 yn
,然后是 yes
,最后是 y
.前三个示例应该使确认功能再次提示用户。我还修补了打印功能,以便 'Please enter y or n!' 消息在测试时不会出现。这不是必需的。
然后我们断言我们的模拟输入被调用了四次,这意味着前三次,确认函数被重新提示。
最后我们断言打印函数被调用(至少一次)'Please enter y or n!'。
这不会测试打印语句的数量是否正确或它们的顺序是否正确,但我怀疑这也是可能的