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

如何让Pytest打补丁的函数仅首次调用触发异常副作用?

解决Pytest测试模板渲染异常分支的问题

你的核心需求是:测试main函数在第一次调用render_template抛异常时,会自动 fallback 到default.html的逻辑。之前的尝试踩了几个坑,下面给你两种简洁的解决办法:

问题分析

  1. 直接把side_effect设为异常实例:每次调用都会抛出异常,导致第二次调用render_template('default.html')也失败。
  2. 用[Exception, None]作为side_effect:不符合业务逻辑,render_template实际不会返回None。
  3. 自定义side_effect时直接调用render_template:因为已经被patch,会触发无限递归调用,导致异常无法终止。

方案一:利用side_effect列表+原函数

先保存render_template的原函数,然后给side_effect设置一个列表:第一次抛异常,第二次调用原函数。

def test_main_exception_fallback(mocker):
    # 获取未被patch的原函数
    from path.to import render_template as original_render
    
    # 打补丁:第一次调用抛异常,第二次调用原函数
    mock_render = mocker.patch(
        "path.to.render_template",
        side_effect=[Exception("mock template error"), original_render]
    )
    
    # 执行测试函数
    result = main("some_path")
    
    # 验证调用逻辑:先调用some_path,再调用default.html
    mock_render.assert_has_calls([
        mocker.call("some_path"),
        mocker.call("default.html")
    ])
    # 验证结果是原函数渲染default.html的返回值
    assert result == original_render("default.html")

方案二:自定义side_effect函数(带调用计数)

用计数器记录调用次数,第一次抛异常,后续调用直接走原函数逻辑,避免递归:

def test_main_exception_fallback(mocker):
    from path.to import render_template as original_render
    call_count = 0

    def mock_render_side_effect(*args, **kwargs):
        nonlocal call_count
        call_count += 1
        if call_count == 1:
            # 第一次调用抛异常
            raise Exception("mock template error")
        # 后续调用走原函数
        return original_render(*args, **kwargs)
    
    mock_render = mocker.patch(
        "path.to.render_template",
        side_effect=mock_render_side_effect
    )
    
    result = main("some_path")
    
    # 验证调用顺序和参数
    mock_render.assert_has_calls([
        mocker.call("some_path"),
        mocker.call("default.html")
    ])
    assert result == original_render("default.html")

关键注意点

  • 必须调用未被patch的原函数:不能在自定义side_effect里直接调用render_template,否则会触发递归调用。
  • 用assert_has_calls验证调用顺序:确保main确实先尝试了指定模板,再fallback到默认模板。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:02:11