You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试被cached装饰的方法仅调用一次内部方法?

问题描述

我使用@cached装饰器(缓存为TTLCache(maxsize=1024, ttl=600))装饰了get_data方法,该方法内部会调用get_result获取结果。编写的测试用例如下:

from cachetools import cached, TTLCache

class MyClass:
    @cached(cache=TTLCache(maxsize=1024, ttl=600))
    def get_data(self, key):
        result = self.get_result(key)
        return result
    
    def get_result(self, key):
        # 实际业务逻辑
        pass

def test_get_data(self):
    my_class = MyClass()
    my_class.get_data.return_value = 'text'
    my_class.get_data('id')
    my_class.get_data('id')
    my_class.get_result.assert_called_once()

执行测试时触发断言错误:

E AssertionError: Expected 'get_result' to have been called once. Called 2 times.

请问如何正确测试该内部方法仅被调用一次?

解决方案

你的测试逻辑存在核心问题:直接给my_class.get_data.return_value赋值,相当于完全Mock了get_data方法,直接绕过了原方法的缓存逻辑和内部调用逻辑。这时候两次调用get_data根本不会触发缓存机制,原方法的逻辑反而被执行了两次,导致get_result被调用两次。

正确的测试方式是Mockget_result方法,让它返回预期值,然后调用get_data两次,验证缓存生效(即get_result仅被调用一次)。修正后的测试代码如下:

基于unittest框架的写法

from unittest.mock import patch
import unittest

class TestMyClass(unittest.TestCase):
    def test_get_data(self):
        my_class = MyClass()
        # Mock get_result方法,指定返回值
        with patch.object(my_class, 'get_result', return_value='text') as mock_get_result:
            # 第一次调用,触发get_result
            result1 = my_class.get_data('id')
            # 第二次调用,应该走缓存,不触发get_result
            result2 = my_class.get_data('id')
            
            # 验证返回值符合预期
            self.assertEqual(result1, 'text')
            self.assertEqual(result2, 'text')
            # 验证get_result仅被调用一次,且参数正确
            mock_get_result.assert_called_once_with('id')

基于pytest框架的写法

from unittest.mock import patch

def test_get_data():
    my_class = MyClass()
    with patch.object(my_class, 'get_result', return_value='text') as mock_get_result:
        result1 = my_class.get_data('id')
        result2 = my_class.get_data('id')
        
        assert result1 == 'text'
        assert result2 == 'text'
        mock_get_result.assert_called_once_with('id')

核心思路:不要Mock被缓存的get_data方法,而是Mock它依赖的get_result方法,让原方法的缓存逻辑正常运行,从而验证缓存是否生效(内部方法是否仅被调用一次)。

内容的提问来源于stack exchange,提问作者Observer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:45:23