测试递归Python函数
我有一个递归函数要测试,但是在测试期间我很难限制递归调用。例如,下面是一个简单的递归函数示例,它调用bool_函数(n)来检查它是否应该中断递归循环测试递归Python函数,python,testing,recursion,mocking,Python,Testing,Recursion,Mocking,我有一个递归函数要测试,但是在测试期间我很难限制递归调用。例如,下面是一个简单的递归函数示例,它调用bool_函数(n)来检查它是否应该中断递归循环 def factorial(n): if bool_function(n): return 1 else: return n * factorial(n-1) 测试或模拟bool_函数(n)的最佳方法是什么,以使其在第一次迭代中为真,在之后的任何调用中为假 除非我希望定期使用调试代码,否则我通常会尽量不留下调试代码
def factorial(n):
if bool_function(n):
return 1
else:
return n * factorial(n-1)
测试或模拟bool_函数(n)的最佳方法是什么,以使其在第一次迭代中为真,在之后的任何调用中为假 除非我希望定期使用调试代码,否则我通常会尽量不留下调试代码,但为了调试,您可以只包含一个默认参数,以强制执行遵循特定路径
def factorial(n, debug=False):
if bool_function(n) or debug:
return 1
else:
return n * factorial(n-1)
这自然意味着您也在外部测试
bool_function()
只需将函数作为参数传递即可。如果函数为“无”,则可以应用一些默认行为(如果需要)
这是大多数语言中对iterables的查询(例如Django查询或Peewee查询)中使用的常用方法
返回布尔值的函数通常称为
您可以始终实现一个类来封装状态,并为您提供更大的灵活性,下面是一个示意图:
>>> class MockBoolCheck:
... def __init__(self, fail_after=0):
... self.count = 0
... self.fail_after = fail_after
... def __call__(self, n):
... called = self.count
... self.count += 1
... return called <= self.fail_after
...
>>> bool_function = MockBoolCheck()
>>> bool_function(42)
True
>>> bool_function(42)
False
>>> bool_function(42)
False
>>> bool_function(42)
False
>>> bool_function(42)
False
>>类MockBoolCheck:
... def uuu init uuu(self,fail_after=0):
... self.count=0
... self.fail\u after=失败后
... 定义调用(self,n):
... 调用=self.count
... self.count+=1
... 返回调用>>bool_函数=MockBoolCheck()
>>>布尔函数(42)
真的
>>>布尔函数(42)
假的
>>>布尔函数(42)
假的
>>>布尔函数(42)
假的
>>>布尔函数(42)
假的
如果除了其他建议的解决方案之外,您真的想要模拟它,并且想要自己(不需要模拟库)通过替换模拟函数来完成
# Your code (or module):
def bool_function(n):
print('REAL bool-function {}'.format(n))
return n <= 0
def factorial(n):
print('FACT {}'.format(n))
if bool_function(n):
return 1
else:
return n * factorial(n-1)
# Mocking code (or module):
def mock_function(n):
print('MOCK bool-function {}'.format(n))
global bool_function
bool_function = bool_func_orig # restore on the first use
return False
bool_func_orig = bool_function
bool_function = mock_function # mock it
# Go run it!
factorial(10)
#您的代码(或模块):
def bool_功能(n):
打印('REAL bool函数{}'。格式(n))
对于python>3.6,返回n
import mock
class RecursividadeTest(unittest.TestCase):
def test_recursive(self):
with mock.patch('path.factorial') as mock_fact:
factorial(3)
self.assertTrue(mock_fact.called)
self.assertGreaterEqual(mock_fact.call_count, 2)
def test_recursive_2(self):
with mock.patch('incolumepy.sequences.fibonacci.fibonacci') as mock_fib:
for i in range(1, 5, -1):
expected = i - 1
fibonacci(i)
self.assertTrue(mock_fib.called)
self.assertEqual(mock_fib.call_count, expected)
你在使用unittest吗?除非bool\u函数
有副作用,否则何必麻烦呢。你不能用n
测试你知道的True
?我强烈建议不要传递任何debug
参数。如果函数无法测试-这意味着设计不好,再增加一个变通方法并不能保证函数本身可以工作。@TarasMatsyk也许这是一个过于简化的例子的结果,但我相信在这种情况下,更大的简单性和可读性超过了模块性。特别是如果谓词仅是一个函数,这种方法既简化了代码的读取,也简化了执行
import mock
class RecursividadeTest(unittest.TestCase):
def test_recursive(self):
with mock.patch('path.factorial') as mock_fact:
factorial(3)
self.assertTrue(mock_fact.called)
self.assertGreaterEqual(mock_fact.call_count, 2)
def test_recursive_2(self):
with mock.patch('incolumepy.sequences.fibonacci.fibonacci') as mock_fib:
for i in range(1, 5, -1):
expected = i - 1
fibonacci(i)
self.assertTrue(mock_fib.called)
self.assertEqual(mock_fib.call_count, expected)