Mocking a class's construction
我刚刚开始使用Python的模拟库来帮助编写更简洁和隔离的单元测试。我的情况是我有一个类,它从一个非常复杂的格式中读取数据,我想在这个类上测试一个方法,该方法在一个干净的格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class holds_data(object): def __init__(self, path): """Pulls complicated data from a file, given by 'path'. Stores it in a dictionary. """ self.data = {} with open(path) as f: self.data.update(_parse(f)) def _parse(self, file): # Some hairy parsing code here pass def x_coords(self): """The x coordinates from one part of the data """ return [point[0] for point in self.data['points']] |
上面的代码是对我所拥有的代码的简化。实际上,
不过,我希望能够在单元测试级别上测试
A test is not a unit test if:
- It touches the filesystem
号
因此,我希望能够修补
1 2 3 4 5 6 | from mock import patch with patch('__main__.holds_data.__init__') as init_mock: init_mock.return_value = None instance = holds_data() instance.data = {'points':[(1,1),(2,2),(3,4)]} assert(instance.x_coords == [1,2,3]) |
号
上面的代码可以工作,但感觉它是以一种相当迂回的方式进行这个测试。有没有更惯用的方法来修补构造函数,或者这是正确的方法?另外,在我的课上或者测试中,是否有一些代码味道我遗漏了?
编辑:很明显,我的问题是,在初始化期间,我的类进行了大量的数据处理来组织将由类似
我的问题是这里是否有代码气味,归根结底就是这个问题:
我敢肯定,如果我重构使
既然您只对测试一种方法感兴趣,那么为什么不模拟整个
1 2 3 4 | >>> mock = MagicMock(data={'points': [(0,1), (2,3), (4,5)]}) >>> mock.x_coords = HoldsData.__dict__['x_coords'] >>> mock.x_coords(mock) [0, 2, 4] |
号
这样,您就可以完全控制
注:在PY3K中,由于没有更多的
这也可以在模拟对象的构造函数中完成:
1 | MagicMock(data={'points': [(0,1), (2,3), (4,5)]}, x_coords=HoldsData.__dict__['x_coords']) |
您基本上遇到了这个问题,原因是:
A test is not a unit test if:
- It touches the filesystem
号
如果您希望遵循此规则,您应该修改
您可以有一个包含相同数据的字符串,然后将这些数据传递给
它看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 | class HoldsData(object): def __init__(self, path): self.data = {} file_data = self._read_data_from_file(path) self.data.update(self._parse(file_data)) def _read_data_from_file(self, path): # read data from file return data def _parse(self, data): # do parsing |
当然,干净的代码会导致干净的测试。最好的情况是模拟数据并向