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。因此,结果取决于测试类中测试用例的数量以及它们运行的顺序,这是我所不希望的。
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'.