如何在Python中Mock方法的默认值?——解决类方法默认参数依赖外部函数的测试难题
问题分析
你遇到的核心问题是Python函数默认参数的求值时机:Python会在函数定义阶段就计算默认参数的值,而不是每次调用函数时。也就是说,当SecondClass被导入/定义的那一刻,get_today()就已经执行了,把当天日期赋值给了method_two的important_date默认参数。之后你再去Mockget_today(),已经无法影响这个提前计算好的默认值了。
你之前尝试修改func_defaults没效果,是因为Python 3里这个属性已经改名为__defaults__了,而且你需要准确地修改SecondClass.method_two的这个属性。
解决方案
根据你的限制(不能Mockmethod_two),这里有两种可行的方式:
方案1:直接修改method_two的默认参数值
既然默认参数是在定义时就固定的,那我们可以在测试时直接替换method_two的__defaults__属性,把它改成我们想要的模拟日期。
示例测试代码:
from unittest.mock import patch from datetime import date from your_module import FirstClass, SecondClass def test_method_one_with_mocked_date(): # 定义我们期望的模拟日期 mock_target_date = date(2023, 12, 25) # 替换SecondClass.method_two的默认参数 with patch.object(SecondClass.method_two, '__defaults__', (mock_target_date,)): # 执行被测试的方法 first_instance = FirstClass() first_instance.method_one() # 这里添加你的断言逻辑,比如验证SecondClass实例的method_two是否使用了mock_target_date # 举个例子,如果method_two会把日期存到实例属性里: # assert first_instance.some_second_class_instance.important_date == mock_target_date
注意要点:
__defaults__是一个元组,顺序对应函数的默认参数顺序。如果method_two的签名是def method_two(self, important_date: datetime.date = get_today()),那么默认参数只有important_date,所以元组里只需要放一个值即可。- 这个修改是临时的,
patch上下文管理器会在测试结束后恢复原来的默认值,不会影响其他测试。
方案2:调整SecondClass.method_two的代码(推荐,更健壮)
如果允许对生产代码做微小调整,建议把默认参数改成延迟求值的方式,这样后续测试会更灵活:
# 修改SecondClass的method_two class SecondClass: def method_two(self, important_date: datetime.date = None): # 只有当参数没传的时候才调用get_today() if important_date is None: important_date = get_today() # 原来的方法逻辑
这样修改后,get_today()会在每次调用method_two且未传important_date时才执行,这时候你就可以正常Mockdate_service.get_today()了:
from unittest.mock import patch from datetime import date from your_module import FirstClass from date_service import get_today def test_method_one_with_mocked_get_today(): mock_target_date = date(2023, 12, 25) with patch('date_service.get_today', return_value=mock_target_date): first_instance = FirstClass() first_instance.method_one() # 执行断言逻辑
这个方案更符合Python的最佳实践,因为默认参数的延迟求值避免了很多类似的测试问题,也让代码更灵活。
内容的提问来源于stack exchange,提问作者xavier
相关产品推荐
相关产品推荐

