嘲弄一个班级的建设

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我通常会习惯的内部结构.我应该在哪里进行交易?清洁代码或清洁测试?

Rik*_*ggi 6

既然你只对测试一种方法感兴趣,为什么不只是模拟整个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)