Python 模拟:如何测试递归函数的调用次数?

scr*_*Dog 2 python recursion unit-testing mocking

我有一个递归函数存在于一个名为 test_module

import requests    

def send_msg(msg, retries=0):
    try:
        # send the message here, e.g. a http request
        response = requests.get("http://www.doesnotexist98734.com")
        # if url does not exist raise an exception
    except Exception as e:
        if retries == 0:
            raise e
        else:
            return send_msg(msg, retries=retries-1)
Run Code Online (Sandbox Code Playgroud)

我的问题是如何编写一个单元测试来检查send_msg当我设置 retries = n 时函数被调用了 n 次。我正在玩模拟模块(我使用的是 python 2.7),我想我想要这样的东西,

import mock, unittest

class MyUnitTest(unittest.TestCase):

    @mock.patch('test_module.send_msg')
    def test_send_msg_tries_n_times(self, mock_send_msg):
        with self.assertRaises(Exception):
            mock_send_msg("hello", retries=3)
        self.assertEqual(mock_send_msg.call_count, 4) # initial call + 3 retries
Run Code Online (Sandbox Code Playgroud)

但是,由于我已经模拟了该函数,因此它不会调用真正的函数,因此我不会收到异常,也不会递归地调用自己...

Mar*_*ers 5

您不能模拟被测函数。您想测试预期结果,而不是函数是否正确使用递归。

模拟request.get()调用,并让它始终产生异常。然后计算你的模拟被调用的频率。

@mock.patch('requests.get')
def test_send_msg_tries_n_times(self, req_get_mock):
    req_get_mock.side_effect = Exception
    with self.assertRaises(Exception):
        send_msg("hello", retries=3)
    self.assertEqual(req_get_mock.call_count, 4)  # 1 initial call + 3 retries
Run Code Online (Sandbox Code Playgroud)

如果将来您想避免使用递归并想改用迭代,您的测试仍然可以工作,因为它验证了行为,而不是特定的实现。您可以安全地重构被测函数。