首页 > 解决方案 > 有没有办法计算使用一组参数调用函数模拟的次数?

问题描述

我有一个模拟 api 调用的函数,如下所示:

def mocked_api_call(animal = animal, soundtype=soundtype)

    output = make_sound(animal, soundtype)

    return output

目标是让模拟在第二次使用相同的参数集调用时返回不同的输出。例如,我希望第一次调用返回“meow”,第二次返回“MEAAAOWWW”,第三次调用返回“mew”,如下所示:

output = mocked_api_call(animal='cat', soundtype = 'meow')
# outputs 'meow'

output = mocked_api_call(animal='cat', soundtype = 'meow')
# outputs 'MEAAAOWWW'

output = mocked_api_call(animal='cat', soundtype = 'meow')
# outputs 'mew'

补丁用于测试使用调用 api 的函数的父函数:

def parent_function(**kwargs):
    response = make_sound(animal=animal, soundtype=soundtype)

测试函数通过一个像这样的monkeypatch调用:

@mock.patch('myscript.api_call', side_effect=mocked_api_call) 
def test_parent_function(*args, **kwargs):
    output = parent_function(**kwargs)

但是我找不到一种方法来生成取决于函数被调用次数的响应。这是你可以用pytest做的吗?

标签: pythonunit-testingautomated-testspytest

解决方案


我不完全确定您的测试会是什么样子,但让我们假设您想要进行不同的测试,其中调用索引在每个测试中都会重置。根据您的需要,以下内容可能对您来说有点过于笼统 - 如果您只需要这样,您也可以将索引传递给make_sound

from unittest import mock
import pytest


class TestSounds:
    indexes = {}
    sounds = {
        ('cat', 'meow'): ('meow', 'MEAAAOWWW', 'mew'),
    }

    @classmethod
    def make_sound(cls, animal, soundtype):
        key = (animal, soundtype)
        if key in cls.sounds:
            index = cls.indexes.setdefault(key, 0)
            sound = cls.sounds[key][index]
            cls.indexes[key] = (index + 1) % len(cls.sounds[key])
            return sound

    # if you need the order not be reset in each test, you can change 
    # the scope to "class"
    @pytest.fixture(scope="function", autouse=True)
    def reset_indexes(self):
        self.__class__.indexes = {}

    def test_parent_function(self, **kwargs):
        with mock.patch('myscript.api_call',
                        side_effect=[self.make_sound(**kwargs),
                                     self.make_sound(**kwargs)]):
            output1 = parent_function(**kwargs)
            output2 = parent_function(**kwargs)

请注意,这是未经测试的,但它可能会给您一些想法。


推荐阅读