Python 的模拟测试介绍(2)

一个简单的删除功能

有时,我们需要从文件系统中删除文件,因此,我们可以写这样的一个函数在Python中,这个函数将使它更容易成为我们的脚本去完成这件事情。

#!/usr/bin/env python# -*- coding: utf-8 -*-import osdef rm(filename):
    os.remove(filename)

很明显,在这个时间点上,我们的rm方法不提供比基本os.remove方法更多的功能,但我们的代码将会有所改进,允许我们在这里添加更多的功能。

让我们写一个传统的测试用例,即,不用模拟测试:

#!/usr/bin/env python# -*- coding: utf-8 -*-from mymodule import rmimport os.pathimport tempfileimport unittestclass RmTestCase(unittest.TestCase):

tmpfilepath = os.path.join(tempfile.gettempdir(), "tmp-testfile")    def setUp(self):
        with open(self.tmpfilepath, "wb") as f:
            f.write("Delete me!")       
    def test_rm(self):
        # remove the file
        rm(self.tmpfilepath)        # test that it was actually removed
        self.assertFalse(os.path.isfile(self.tempfile), "Failed to remove the file.")

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

重构与模拟测试

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

#!/usr/bin/env python# -*- coding: utf-8 -*-from mymodule import rmimport mockimport 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的每个模块来保持自己的进口。

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4f7480c272ffe8e2f9863c15b27b0b31.html