如何在测试案例中模拟uuid生成?

phy*_*ion 5 python iterator mocking python-unittest

我有其中的设置,我创造,我想嘲笑函数的对象测试用例uuid4的模块中uuid

TEST_UUIDS = ['uuid_{}'.format(i) for i in range(10000)]
UUID_POOL = iter(TEST_UUIDS)

def generate_uuid() -> str:
    return next(UUID_POOL)

class MyTestCase(TestCase):

    def setUp(self, **kwargs):
        self._create_my_object

    @patch.object(uuid, 'uuid4', generate_uuid)
    def _create_my_object(self):
        # Create an object using a uuid
Run Code Online (Sandbox Code Playgroud)

现在的问题是,当我编写两个测试用例时,第二次创建对象时,第一次获得其他uuid。因此,结果取决于测试类中测试用例的数量以及它们运行的​​顺序,这是我所不希望的。

  • 这是模拟uuid生成器的最佳方法吗?
  • 如何在每次调用setUp(或tearDown)时重置或重新创建迭代器?

phy*_*ion 7

The answer was easier than I thought: just don't use iterators! Instead, set the list of uuids as side_effect of the mock.

TEST_UUIDS = ['uuid_{}'.format(i) for i in range(10000)]

class MyTestCase(TestCase):

    def setUp(self, **kwargs):
        self._create_my_object

    @patch.object(uuid, 'uuid4', side_effect=TEST_UUIDS)
    def _create_my_object(self):
        # Create an object using a uuid
Run Code Online (Sandbox Code Playgroud)

EDIT

I found an even nicer way to write this as a context manager, which allows for prefixing uuids based on the context.

TEST_UUIDS = ['uuid_{}'.format(i) for i in range(10000)]

def uuid_prefix(prefix: str):
    return patch.object(uuid, 'uuid4', side_effect=['{}_{}'.format(prefix, x) for x in TEST_UUIDS])

class MyTestCase(TestCase):

    def setUp(self, **kwargs):
        self._create_my_object

    def _create_my_object(self):
        with uuid_prefix('obj_a'):
            # Create an object A using a uuid
        with uuid_prefix('obj_b'):
            # Create an object B using a uuid
Run Code Online (Sandbox Code Playgroud)

Explanation: I am mocking the function uuid.uuid4 using patch.object(uuid, 'uuid4'). In it, I define a side effect as a list. If your side effect is a list, it can be seen as a list of return values of that function on subsequent calls, so the first time the function uuid4() is called, it returns the first element of that list, the second time the second element, etc. If in the with-context I am generating 10 objects A, the UUIDs will be 'obj_a_uuid_0' up to 'obj_a_uuid_9'.

  • 关于`side_effect`的更多细节可以在这里找到:https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect (3认同)