Python:用于数组的Mock Patch模块

1 投票
3 回答
2038 浏览
提问于 2025-04-18 16:53

这是我的方法:

def _eda_workflow(self, workflow_id, account_id):
    uuids = [str(uuid.uuid4()) for x in range(2)]

    return {
        'id': workflow_id,
        'root': uuids[0],
        'accountId': account_id,
        'steps': [
            {
                'this': uuids[0],
                'next': [uuids[1]],
                'type': 'on-contact-signed-up',
                'displayName': 'Sign Up',
                'constraints': {},
            },
            {
                'this': uuids[1],
                'prev': uuids[0],
                'next': [],
                'type': 'on-time-elapsed',
                'displayName': 'Send the email after delay or not!',
                'delay': 'PT0M',
                'sideEffect': {
                    'task': 'sendEmail',
                    'constraints': {},
                    'mailing_data': {},
                    'email': {}
                }
            }
        ]
    }

我遇到的问题是,当我写这个的时候

def generate_uuids():
    return ["10e6e848-dc77-4057-890e-5acd4ed9aeb3", "d8d501a7-f7e7-4423-921c-e0f39b7e1301"]

@mock.patch('path.to.uuid')
def test_translte_workflow(self, uuid_mock):
   uuid_mock.uuid4.side_effect = generate_uuids

返回的方法给我返回的是一个列表的值,而不是我期待的结果。我不太确定该怎么正确地写这个测试。

3 个回答

1

我遇到了一个类似的问题,经过一些尝试,我发现使用可迭代对象配合 @patchside_effect 更好。在我的情况下,我不是填充一个数组,而是填充一个比我测试中的函数更深一层的函数的返回值。

TEST_UUIDS = ["10e6e848-dc77-4057-890e-5acd4ed9aeb3",
              "d8d501a7-f7e7-4423-921c-e0f39b7e1301"]
TEST_UUID_POOL = iter(TEST_UUIDS)

@patch('path.to.function1', side_effect=TEST_UUID_POOL)
def test_translate_workflow(self, uuid_mock):
    # function 1 is called twice in function2
    function2()
2

你的 generate_uuids 函数返回的是一个 UUID 的 列表,所以你得到的就是这个。

如果你想要一个函数,每次只返回一个 UUID,并且这个 UUID 是从正好两个 UUID 中选出来的,你可以从这两个 UUID 的列表中创建一个 迭代器,然后在这个函数中返回 iterator.next()。如果你还想对这些 UUID 进行一些检查,可以把它们单独存放,不要和迭代器放在一起:

import mock
import unittest
import uuid


TEST_UUIDS = ["10e6e848-dc77-4057-890e-5acd4ed9aeb3",
              "d8d501a7-f7e7-4423-921c-e0f39b7e1301"]


uuid_pool = iter(TEST_UUIDS)


def generate_uuid():
    return uuid_pool.next()


def func():
    uuid_1 = uuid.uuid4()
    uuid_2 = uuid.uuid4()
    return [uuid_1, uuid_2]


class TestUUIDs(unittest.TestCase):

    @mock.patch('uuid.uuid4', generate_uuid)
    def test_uuid_mock(self):
        actual = func()
        expected = TEST_UUIDS
        self.assertEquals(expected, actual)


unittest.main()

一旦你用完了这个迭代器(取出两个元素后),它会抛出 StopIteration 的错误。

如果你想创建一个函数,它总是从一个无尽的 UUID 流中返回一个 UUID,你可以使用 itertools.cycle

from itertools import cycle

uuid_pool = cycle(["10e6e848-dc77-4057-890e-5acd4ed9aeb3",
                   "d8d501a7-f7e7-4423-921c-e0f39b7e1301"])
3

副作用就是指在每次调用这个模拟对象时,额外发生的一些事情。我觉得这正是你想要的内容:

def fake_uuid4():
    yield "10e6e848-dc77-4057-890e-5acd4ed9aeb3"
    yield "d8d501a7-f7e7-4423-921c-e0f39b7e1301"

@mock.patch('path.to.uuid.uuid4', fake_uuid4().next)
def test_translte_workflow(self):
   ...

撰写回答