问题
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