如何测试函数是否在指定上下文管理器中被调用?
能测试
my_function是否在my_context_manager上下文中调用吗? 当然可以,下面是几种实用的测试方式:
1. 用unittest.mock跟踪调用顺序
通过Mock对象记录上下文管理器的__enter__、__exit__方法,以及my_function的调用,然后验证调用顺序——必须是先进入上下文,再调用函数,最后退出上下文。
示例代码:
from unittest.mock import Mock, call def test_function_runs_in_context(): # 模拟上下文管理器和目标函数 mock_ctx = Mock() mock_func = Mock() # 执行要测试的逻辑 with mock_ctx(): mock_func() # 验证上下文先进入,函数再调用,最后退出 assert mock_ctx().__enter__.called assert mock_func.called assert mock_ctx().__exit__.called # 检查调用顺序是否正确 all_calls = mock_ctx.mock_calls + mock_func.mock_calls enter_call_idx = next(i for i, call in enumerate(all_calls) if call[0] == '().__enter__') func_call_idx = next(i for i, call in enumerate(all_calls) if call[0] == '') exit_call_idx = next(i for i, call in enumerate(all_calls) if call[0] == '().__exit__') assert enter_call_idx < func_call_idx < exit_call_idx
2. 给上下文管理器加状态标记
如果能修改上下文管理器的代码,可以给它加个状态属性,比如is_active,然后在函数里或者测试中检查这个状态:
示例代码:
# 自定义带状态的上下文管理器 class MyContextManager: def __init__(self): self.is_active = False def __enter__(self): self.is_active = True return self def __exit__(self, exc_type, exc_val, exc_tb): self.is_active = False def my_function(ctx): # 函数内部直接验证上下文是否激活 assert ctx.is_active, "my_function必须在上下文管理器中调用" def test_in_context(): ctx = MyContextManager() with ctx: my_function(ctx) # 这里断言通过 # 退出上下文后状态应该重置 assert not ctx.is_active
3. 用副作用捕获上下文状态
如果不想修改原上下文管理器,可以给Mock的__enter__和__exit__加副作用,记录当前是否处于上下文内,然后在函数调用时验证:
from unittest.mock import Mock def test_with_side_effect(): in_context = False def enter(): nonlocal in_context in_context = True def exit(*args): nonlocal in_context in_context = False mock_ctx = Mock() mock_ctx().__enter__.side_effect = enter mock_ctx().__exit__.side_effect = exit def my_function(): assert in_context, "函数不在上下文里执行" with mock_ctx(): my_function() # 断言通过
内容的提问来源于stack exchange,提问作者Dušan Maďar
相关产品推荐
相关产品推荐

