use*_*000 5 python unit-testing python-unittest
我使用的类有一个方法shuffle,该方法返回调用它的实例的打乱版本。这是:
shuffled_object = unshuffled_object.shuffle(buffer_size)
我想模拟这个方法,以便在调用它时,它只返回自身,而不进行任何改组。以下是这种情况的简化:
# my_test.py
class Test():
def shuffle(self, buffer_size):
return self
Run Code Online (Sandbox Code Playgroud)
# test_mock
import unittest
import unittest.mock as mk
import my_test
def mock_test(self, buffer_size):
return self
class TestMock(unittest.TestCase):
def test_mock(self):
with mk.patch('my_test.Test.shuffle') as shuffle:
shuffle.side_effect = mock_test
shuffled_test = my_test.Test().shuffle(5)
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试这样做时,我收到以下错误:
TypeError: mock_test() missing 1 required positional argument: 'buffer_size'
Run Code Online (Sandbox Code Playgroud)
仅使用参数调用该方法5,调用实例不会将其自身作为self参数传递给该方法。是否可以通过模块实现这样的行为unittest.mock?
真正的代码是这样的:
# input.py
def create_dataset():
...
raw_dataset = tf.data.Dataset.from_generator(data_generator, output_types, output_shapes)
shuffled_dataset = raw_dataset.shuffle(buffer_size)
dataset = shuffled_dataset.map(_load_example)
...
return dataset
Run Code Online (Sandbox Code Playgroud)
# test.py
def shuffle(self, buffer_size):
return self
with mk.patch(input.tf.data.Dataset.shuffle) as shuffle_mock:
shuffle_mock.side_effect = shuffle
dataset = input.create_dataset()
Run Code Online (Sandbox Code Playgroud)
这里的大问题是我只想模拟该shuffle方法,因为我不希望它在测试时是随机的,但我想保留其余的原始方法,以便我的代码可以继续工作。棘手的部分是,它shuffle不仅对调用它的实例进行洗牌,而且还返回洗牌后的实例,因此我想在测试时返回数据集的未洗牌版本。
另一方面,让模拟继承并不那么简单,tf.data.Dataset因为据我了解,它Dataset似乎是一个具有抽象方法的抽象类,并且我想从Dataset初始化程序from_generator创建的任何子类型中抽象出自己。
我通过修补该方法更进一步,如下所示:
def shuffle(cls, buffer_size, seed=None, reshuffle_each_iteration=None):
def _load_example(example):
return example
return cls.map(cls, _load_example)
from data_input.kitti.kitti_input import tf as tf_mock
with mk.patch.object(tf_mock.data.Dataset, 'shuffle', classmethod(shuffle)):
dataset = create_dataset()
Run Code Online (Sandbox Code Playgroud)
现在,实例raw_dataset似乎将自身作为self的参数传递shuffle,但无论出于何种原因,代码仍然崩溃并出现以下错误:
AttributeError: 'property' object has no attribute '_flat_types'
Run Code Online (Sandbox Code Playgroud)
所以我认为这self在某种程度上不完全是调用实例,它在某种程度上是内部不同的。
我想我已经找到了解决问题的合理方法。我没有尝试修补shuffle的方法tf.data.Dataset,而是认为如果我有权访问它,我可以直接在要测试的实例上更改它。因此,我尝试修补创建实例的方法tf.data.Dataset.from_generator,以便它调用原始方法,但在返回新创建的实例之前,它shuffle用另一种仅返回未更改的数据集的方法替换其方法。代码如下:
from_generator_old = tf.data.Dataset.from_generator
def from_generator_new(generator, output_types, output_shapes=None, args=None):
dataset = from_generator_old(generator, output_types, output_shapes, args)
dataset.shuffle = lambda *args, **kwargs: dataset
return dataset
from data_input.kitti.kitti_input import tf as tf_mock
with mk.patch.object(tf_mock.data.Dataset, 'from_generator', from_generator_new):
dataset = input.create_dataset()
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但我不确定这是否是正确的方法。如果有人有更好的想法或能想到我不应该这样做的原因,欢迎提出建议或其他答案,但到目前为止我认为这是最好的选择。如果没有人提出更好的建议,我想我会将其标记为已接受的答案。
我已经找到了解决这个问题的更好方法。经过一番阅读后,我发现了有关模拟未绑定方法的解释。显然,当与设置为 的参数一起mock.patch.object使用时,会维护修补方法的签名,并在幕后调用该方法的模拟版本。然后,该方法将绑定到调用它的实例(即将实例作为参数)。解释可以在以下链接中找到:autospecTrueself
https://het.as.utexas.edu/HET/Software/mock/examples.html#mocking-unbound-methods
在测试时,我还发现,当使用tf.test.TestCase类而不是unittest.TestCase进行测试时,整个计算图的随机种子似乎是固定的,因此shuffle在这个框架下每次测试的结果都会相同。然而,这似乎根本没有记录,所以我不确定盲目依赖它是否是一个好主意。
| 归档时间: |
|
| 查看次数: |
5466 次 |
| 最近记录: |