Python的Mock模拟测试介绍(2)

发表于:2014-03-21来源:DiggerPlus作者:DiggerPlus点击数: 标签:模拟测试
我们的测试用例是相当简单的,但当它每次运行时,一个临时文件被创建然后被删除。此外,我们没有办法去测试我们的rm方法是否传递参数到os.remove中。

  我们的测试用例是相当简单的,但当它每次运行时,一个临时文件被创建然后被删除。此外,我们没有办法去测试我们的rm方法是否传递参数到os.remove中。我们可以假设它是基于上面的测试,但仍有许多需要被证实。

  重构与模拟测试

  让我们使用mock重构我们的测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from mymodule import rm
import mock
import unittestclass 
 
RmTestCase(unittest.TestCase):
 
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

  对于这些重构,我们已经从根本上改变了该测试的运行方式。现在,我们有一个内部的对象,让我们可以使用另一个功能验证。

  潜在的陷阱

  第一件要注意的事情就是,我们使用的mock.patch方法的装饰位于mymodule.os模拟对象,并注入到我们测试案例的模拟方法。是模拟os更有意义,还是它在mymodule.os的参考更有意义?

  当然,当Python出现在进口和管理模块时,用法是非常的灵活。在运行时,该mymodule模块有自己的os操作系统——被引入到自己的范围内的模块。因此,如果我们模拟os系统,我们不会看到模拟测试在mymodule模块的影响。

  这句话需要深刻的记住:

  模拟测试一个项目,只需要了解它用在哪里,而不是它从哪里来.

  如果你需要为myproject.app.MyElaborateClass模拟tempfile模型,你可能需要去模拟myproject.app.tempfile的每个模块来保持自己的进口。

  这就是用陷阱的方式来模拟测试。

  向’rm’中加入验证

  之前定义的 rm 方法相当的简单 . 在盲目的删除之前,我们会拿它来验证一个路径是否存在,并验证其是否是一个文件. 让我们重构 rm 使其变得更加聪明:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import os
import os.path
 
def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

  很好. 现在,让我们调整我们的测试用例来保持测试的覆盖程度.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from mymodule import rm
import mock
import unittestclass 
 
RmTestCase(unittest.TestCase):
 
    @mock.patch('mymodule.os.path')
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os, mock_path):
        # set up the mock
        mock_path.isfile.return_value = False
 
        rm("any path")        
        # test that the remove call was NOT called.
        self.assertFalse(mock_os.remove.called, "Failed to not remove the file if not present.")        
        # make the file 'exist'
        mock_path.isfile.return_value = True
 
        rm("any path")
 
        mock_os.remove.assert_called_with("any path")

原文转自:http://www.diggerplus.org/archives/2704