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

如何在Pytest中为循环内的同一函数Mock不同返回值?

测试循环列表场景下Mock返回值的问题解决

现有处理汽车喷漆的函数:

def do_operate(car_list: list):
    flawless_car_list = list()
    for car in car_list:
        if paint_the_car(car):
            flawless_car_list.append(car)
        else:
            print_log(f"{car} couldn't get painted")

    return flawless_car_list

paint_the_car可能随机返回False,需要测试第二辆车喷漆失败,其余成功的场景,确保程序继续处理后续车辆并记录日志。快乐路径测试已实现:

def test_happy_path(mocker):
    test_list = ["honda", "bmw", "ford"]
    mocker.patch("pytest1.paint_the_car", return_value=True)
    mocker.patch("pytest1.print_log")

    card_list = do_operate(car_list=test_list)

    assert len(card_list) == 3
    paint_the_car.assert_called()
    print_log.assert_not_called()

待修改的测试函数需要满足断言:

def test_error_occured_on_second_item(mocker):
    test_list = ["honda", "bmw", "ford"]

    # HOW TO CHANGE MOCKS?
    mocker.patch("pytest1.paint_the_car", return_value=True)
    mocker.patch("pytest1.print_log")

    card_list = do_operate(car_list=test_list)

    assert len(card_list) == 2
    paint_the_car.assert_called()
    print_log.assert_called_with("bmw couldn't get painted")

解决方案

方法1:使用side_effect按顺序返回值

mock.patch的side_effect参数可以接受一个列表,Mock会按调用顺序依次返回列表中的值。针对这个场景,传入[True, False, True]即可对应三辆车的返回结果:

def test_error_occured_on_second_item(mocker):
    test_list = ["honda", "bmw", "ford"]

    # 修改paint_the_car的Mock,按顺序返回True、False、True
    mocker.patch("pytest1.paint_the_car", side_effect=[True, False, True])
    mock_print_log = mocker.patch("pytest1.print_log")

    card_list = do_operate(car_list=test_list)

    assert len(card_list) == 2
    # 验证paint_the_car被按顺序调用三次
    paint_the_car.assert_has_calls([
        mocker.call("honda"),
        mocker.call("bmw"),
        mocker.call("ford")
    ])
    mock_print_log.assert_called_with("bmw couldn't get painted")

方法2:使用自定义函数根据参数返回

如果需要更灵活的逻辑(比如根据车辆名称判断返回值),可以给side_effect传入自定义函数:

def test_error_occured_on_second_item(mocker):
    test_list = ["honda", "bmw", "ford"]

    # 自定义函数:仅当车辆是"bmw"时返回False,其余返回True
    def mock_paint(car):
        return car != "bmw"

    mocker.patch("pytest1.paint_the_car", side_effect=mock_paint)
    mock_print_log = mocker.patch("pytest1.print_log")

    card_list = do_operate(car_list=test_list)

    assert len(card_list) == 2
    mock_print_log.assert_called_with("bmw couldn't get painted")

关键说明

  • side_effect比return_value更适合动态返回值场景,支持列表、函数、异常等多种类型。
  • 方法1适合固定顺序的返回需求,方法2适合需要根据输入参数判断返回值的场景,按需选择即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 00:21:26