Wil*_*uck 11 python unit-testing mocking
我刚刚开始使用Python的模拟库来帮助编写更简洁和隔离的单元测试.我的情况是我有一个类从一个非常多毛的格式读取数据,我想在这个类上测试一个以干净格式呈现数据的方法.
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']]
Run Code Online (Sandbox Code Playgroud)
上面的代码简化了我的工作.实际上,这_parse
是一个相当重要的方法,我在功能级别上进行了测试.
但是,我希望能够x_coords
在单元测试级别进行测试.如果我通过给它一个路径来实例化这个类,它将违反单元测试的规则,因为:
在以下情况下,测试不是单元测试:
- 它涉及文件系统
所以,我希望能够修改__init__
方法holds_data
,然后只需填写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])
Run Code Online (Sandbox Code Playgroud)
上面的代码有效,但感觉就像是以相当迂回的方式进行这个测试.是否有更惯用的方法来修补构造函数,或者这是正确的方法吗?此外,是否有一些代码气味,无论是在我的班级还是我缺少的测试中?
编辑:要清楚,我的问题是在初始化期间,我的类会进行大量的数据处理,以组织将通过类似方法呈现的数据x_coords
.我想知道修补所有这些步骤的最简单方法是什么,而不必提供输入的完整示例.我想只测试x_coords
我控制它使用的数据的情况下的行为.
我在这里是否有代码味道的问题归结为这个问题:
如果我重构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]
Run Code Online (Sandbox Code Playgroud)
这样您就可以完全控制x_coords
输入和输出(通过副作用或返回值).
注意:在py3k中你可以做到,mock.x_coords = HoldsData.x_coords
因为没有更多unbound methods
.
这也可以在mock对象的构造函数中完成:
MagicMock(data={'points': [(0,1), (2,3), (4,5)]}, x_coords=HoldsData.__dict__['x_coords'])
Run Code Online (Sandbox Code Playgroud)