我有一个可以按预期工作的单元测试,但是我觉得这不是用pytest测试多个输入的最佳方法。它绝对违反了DRY原则。我认为有一个更好的方法可以解决此问题,但我不知道该怎么办。我也不确定该模拟的实际用途。它未使用,但必须存在(请参见下面代码中函数中的“ mock_choice”参数)。
我认为遍历所有呼叫可能会奏效,但并没有按预期进行。除了使用side_effects并调用四次以确保获得预期的返回值外,我真的找不到其他方法。
要测试的功能
def export_options():
while True:
try:
choice = int(input("\nPlease make a selection"))
if choice in ([option for option in range(1, 5)]):
return choice # This what I'm testing
else:
print("\nNot a valid selection\n")
except ValueError as err:
print("Please enter an integer")
测试功能
@mock.patch('realestate.app.user_inputs.input', side_effect=[1, 2, 3, 4])
def test_export_options_valid_choice(mock_choice): # mock_choice needs to be here but isn't used!
export_option = user_inputs.export_options()
assert export_option == 1
export_option = user_inputs.export_options()
assert export_option == 2
export_option = user_inputs.export_options()
assert export_option == 3
export_option = user_inputs.export_options()
assert export_option == 4
测试有效。它在函数返回介于1和4之间的所有值时通过。但是,由于代码非常重复,因此我想知道是否有更好的方法来测试多个输入调用,因为我想将其应用于以后的测试。 / p>
答案 0 :(得分:2)
您可以使用for循环来避免重复代码。
@mock.patch('realestate.app.user_inputs.input')
def test_export_options_valid_choice(self, mock_choice):
for response in [1, 2, 3, 4]:
with self.subTest(response=response)
mock_choice.return_value = response
export_option = user_inputs.export_options()
self.assertEqual(export_option, response)
# Not in original version, but other tests might need it.
mock_choice.assert_called_once_with("\nPlease make a selection")
mock_choice.reset_mock()
subtest context manager会告诉您哪个输入失败。
做这样的事情的唯一方法是使用unittest模块进行子测试吗?我知道pytest不支持子测试,但我希望存在类似的黑客行为。
您当然可以在不使用子测试的情况下进行循环,但是您可能很难分辨出哪个输入失败。更一般地,您可以为每个测试调用一个通用的辅助函数,而不是循环。
特别是对于pytest,您可以使用@pytest.mark.parametrize
装饰器来自动执行此操作。
@pytest.mark.parametrize('response', [1, 2, 3, 4])
@mock.patch('realestate.app.user_inputs.input')
def test_export_options_valid_choice(mock_choice, response):
mock_choice.return_value = response
export_option = user_inputs.export_options()
assert export_option == response