我正在尝试模拟
unittest
中的某些对象,但我需要根据在 Mock
语句中评估的 if
对象返回不同的布尔值。
我正在测试的功能看起来像这样:
def run_tests():
failed_tests = []
for test in get_tests():
if validate_schema(test):
#some logic
else:
failed_tests.append(test)
return failed_tests
def validate_schema(test):
if test == foo:
return True
else:
return False
例如,我想做
for
循环的三次迭代,其中前两次迭代 validate_schema()
返回 False
,第三次返回 True
。
我的单元测试看起来像这样,试图实现这一目标:
import unittest
from unittest.mock import Mock, patch
from app.test_runner import run_tests
MOCK_TEST_CASE_ONE = Mock()
MOCK_TEST_CASE_TWO = Mock()
MOCK_TEST_CASE_THREE = Mock()
class TestRunTests(unittest.TestCase):
@patch('app.test_extractor.get_tests')
@patch('app.test_parser.validate_schema')
def test_two_fail_one_pass_test_on_validation(self, mock_get_tests, mock_validate_schema):
mock_get_unit_tests.return_value = [MOCK_TEST_CASE_ONE, MOCK_TEST_CASE_TWO, MOCK_TEST_CASE_THREE]
validation_results = [False, False, True]
mock_validate_schema.side_effect = validation_results
self.assertEqual(run_tests(), [MOCK_TEST_CASE_ONE, MOCK_TEST_CASE_TWO])
if __name__ == "__main__":
unittest.main()
但是,运行测试时,测试在
mock_validate_schema.side_effect = validation_results
上失败,因为它返回错误 TypeError: 'bool' object is not iterable
。
我尝试过遵循这个类似的示例如何在for循环中动态模拟python函数的结果?但区别在于
foo
接受一组项目,而我正在尝试评估 Mock
对象,所以我不确定如何评估前两个 Mock 对象以返回 False
和第三个True
。
经过大量研究和尝试,我找出了问题所在,感谢我偶然发现的这篇文章https://nedbatchelder.com/blog/202202/why_your_mock_still_doesnt_work.html
测试函数参数中的修补顺序需要按照装饰器的调用方式从后到前排列。最初我的测试函数参数看起来像这样:
@patch('app.test_extractor.get_tests')
@patch('app.test_parser.validate_schema')
def test_two_fail_one_pass_test_on_validation(self, mock_get_tests, mock_validate_schema):
但是
mock_get_tests
和 mock_validate_schema
需要这样切换:
@patch('app.test_extractor.get_tests')
@patch('app.test_parser.validate_schema')
def test_two_fail_one_pass_test_on_validation(self, mock_validate_schema, mock_get_tests):
单元测试的其余部分实际上很好,现在可以工作了,所以现在看起来像
import unittest
from unittest.mock import Mock, patch
from app.test_runner import run_tests
MOCK_TEST_CASE_ONE = Mock()
MOCK_TEST_CASE_TWO = Mock()
MOCK_TEST_CASE_THREE = Mock()
class TestRunTests(unittest.TestCase):
@patch('app.test_extractor.get_tests')
@patch('app.test_parser.validate_schema')
def test_two_fail_one_pass_test_on_validation(self, mock_validate_schema, mock_get_tests):
mock_get_unit_tests.return_value = [MOCK_TEST_CASE_ONE, MOCK_TEST_CASE_TWO, MOCK_TEST_CASE_THREE]
validation_results = [False, False, True]
mock_validate_schema.side_effect = validation_results
self.assertEqual(run_tests(), [MOCK_TEST_CASE_ONE, MOCK_TEST_CASE_TWO])
if __name__ == "__main__":
unittest.main()