我刚刚开始使用 Python 的 mock库来帮助编写更简洁和独立的单元测试。我的情况是我有一个类可以从非常多毛的格式中读取数据,我想测试这个类上的一个方法,它以干净的方式呈现数据 格式。
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']]
上面的代码是对我现有代码的简化。实际上,_parse
是一种相当重要的方法,我在功能级别对其进行了测试。
不过,我希望能够在单元测试级别测试 x_coords
。如果我通过给它一个路径来实例化这个类,它会违反 rules of unit tests因为:
A test is not a unit test if:
- It touches the filesystem
所以,我希望能够为 holds_data
修补 __init__
方法,然后只需填写 self.data
的部分> x_coords
需要。像这样的东西:
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])
上面的代码有效,但感觉它是以一种相当迂回的方式进行此测试。是否有更惯用的方法来修补构造函数,或者这是正确的方法吗?另外,在我的类或测试中是否存在我遗漏的代码味道?
编辑:需要明确的是,我的问题是在初始化期间,我的类进行了大量数据处理以组织将由 x_coords
之类的方法呈现的数据>。我想知道什么是修补所有这些步骤的最简单方法,而无需提供完整的输入示例。我只想在我控制它使用的数据的情况下测试 x_coords
的行为。
我这里有没有code smell的问题归结为这个问题:
我敢肯定,如果我将 x_coords
重构为一个将 holds_data
作为参数的独立函数,这会更容易。如果“更容易测试 == 更好的设计”成立,那么这就是要走的路。但是,它需要 x_coords
函数来了解更多关于 holds_data
内部的信息,而我通常会对此感到满意。我应该在哪里进行权衡?更简洁的代码还是更简洁的测试?
最佳答案
既然您只对测试一种方法感兴趣,为什么不模拟整个 HoldsData
类并在其上固定 x_coords
方法?
>>> mock = MagicMock(data={'points': [(0,1), (2,3), (4,5)]})
>>> mock.x_coords = HoldsData.__dict__['x_coords']
>>> mock.x_coords(mock)
[0, 2, 4]
这样您就可以完全控制x_coords
输入和输出(通过副作用或返回值)。
注意:在 py3k 中你可以只做 mock.x_coords = HoldsData.x_coords
因为有 no more unbound methods
.
这也可以在模拟对象的构造函数中完成:
MagicMock(data={'points': [(0,1), (2,3), (4,5)]}, x_coords=HoldsData.__dict__['x_coords'])
关于python - 模拟类的构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9980962/