测试人必会的Python 的mock模拟测试

如何不靠耐心测试

可能我们正在写一个社交软件并且想测试一下“发布到Facebook的功能”,但是我们不希望每次运行测试集的时候都发布到Facebook上。

Python的unittest库中有一个子包叫unittest.mock——或者你把它声明成一个依赖,简化为mock——这个模块提供了非常强大并且有用的方法,通过它们可以模拟或者屏敝掉这些不受我们希望的方面。

注意:mock是最近收录在Python 3.3标准库中的;之前发布的版本必须通过 PyPI下载Mock库。

恐惧系统调用

无论你是想写一个脚本弹出一个CD驱动,或者是一个web服务用来删除/tmp目录下的缓存文件,或者是一个socket服务来绑定一个TCP端口,这些调用都是在你单元测试的时候是不被希望的方面。

作为一个开发人员,你更关心你的库是不是成功的调用了系统函数来弹出CD,而不是体验每次测试的时候CD托盘都打开。

对于我们的第一个例子,我们要重构一个从原始到使用mock的一个标准Python测试用例。我们将会证明如何用mock写一个测试用例使我们的测试更智能、更快,并且能暴露更多关于我们的软件工作的问题。

一个简单的删除功能

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

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

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

#!/usr/bin/env python# 
-*- coding: utf-8 -*-
from mymodule import rm
import os.path
import tempfile
import unittest
class 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 rm
import mock
import unittest

class 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")

对于这些重构,我们已经从根本上改变了该测试的运行方式。

现在,mymodule模块中的os对象已经被mock对象替换,当调用mymodule的os模块的remove方法时,实际调用的是mock_os这个mock对象的remove方法。

向‘rm’中加入验证

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

#!/usr/bin/env python# 
-*- coding: utf-8 -*-
import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

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

#!/usr/bin/env python# 
-*- coding: utf-8 -*-
from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值