How to mock uuid generation in a test case?

匆匆过客 提交于 2020-05-28 20:51:51

问题


I have a test case in which in the setUp, I create an object for which I want to mock the function uuid4 in the module 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

My problem now is that when I run write two test cases, the second time the object is created, it gets other uuids as the first time. Therefore, the result is dependent on the number of test cases in my test class and the order they are run in, something I don't want.

  • Is this the best way to mock a uuid generator?
  • How do I reset or recreate the iterator at every call of setUp (or tearDown)?

回答1:


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

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

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'.




回答2:


I found an even nicer solution:

TEST_UUIDS_COUNT = 0
def mock_uuid():
    global TEST_UUIDS_COUNT
    TEST_UUIDS_COUNT += 1
    return uuid.UUID(int=TEST_UUIDS_COUNT)

class MyTestCase(TestCase):

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

    @patch('uuid.uuid4', mock_uuid)
    def _create_my_object(self):
        # Create an object using a uuid

This way it is universal and works with all edge cases.



来源:https://stackoverflow.com/questions/44395755/how-to-mock-uuid-generation-in-a-test-case

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!