加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 安全 > 正文

Mock在Python单元测试中的使用

发布时间:2021-01-10 23:43:45 所属栏目:安全 来源:网络整理
导读:《Mock在Python单元测试中的使用》要点: 本文介绍了Mock在Python单元测试中的使用,希望对您有用。如果有疑问,可以联系我们。 本文讲述的是 Python 中 Mock 的使用. 如何执行单元测试而不用考验你的耐心 很多时候,我们编写的软件会直接与那些被标记为“垃

因为我们的测试覆盖了?RemovalService,因此我们不会对我们测试用例中?UploadService?的内部函数?rm?进行验证.相反,我们将调用?UploadService?的?RemovalService.rm?方法来进行简单测试(当然没有其他副作用),我们通过之前的测试用例便能知道它可以正确地工作.

这里有两种方法来实现测试:

  1. 模拟 RemovalService.rm 方法本身.
  2. 在 UploadService 的构造函数中提供一个模拟实例.

因为这两种方法都是单元测试中非常重要的方法,所以我们将同时对这两种方法进行回顾.

方法 1:模拟实例的方法

mock?库有一个特殊的方法装饰器,可以模拟对象实例的方法和属性,即?@mock.patch.object decorator?装饰器:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from mymodule import RemovalService, UploadService
  4. import mock
  5. import unittest
  6. class RemovalServiceTestCase(unittest.TestCase):
  7. ? ?@mock.patch('mymodule.os.path')
  8. ? ?@mock.patch('mymodule.os')
  9. ? ?def test_rm(self, "Failed to not remove the file if not present.")
  10. ? ? ? ?# make the file 'exist'
  11. ? ? ? ?mock_path.isfile.return_value = True
  12. ? ? ? ?reference.rm("any path")
  13. ? ? ? ?mock_os.remove.assert_called_with("any path")
  14. class UploadServiceTestCase(unittest.TestCase):
  15. ? ?@mock.patch.object(RemovalService, 'rm')
  16. ? ?def test_upload_complete(self, mock_rm):
  17. ? ? ? ?# build our dependencies
  18. ? ? ? ?removal_service = RemovalService()
  19. ? ? ? ?reference = UploadService(removal_service)
  20. ? ? ? ?# call upload_complete, which should, in turn, call `rm`:
  21. ? ? ? ?reference.upload_complete("my uploaded file")
  22. ? ? ? ?# check that it called the rm method of any RemovalService
  23. ? ? ? ?mock_rm.assert_called_with("my uploaded file")
  24. ? ? ? ?# check that it called the rm method of _our_ removal_service
  25. ? ? ? ?removal_service.rm.assert_called_with("my uploaded file")

非常棒!我们验证了?UploadService?成功调用了我们实例的?rm?方法.你是否注意到一些有趣的地方?这种修补机制(patching mechanism)实际上替换了我们测试用例中的所有?RemovalService?实例的?rm?方法.这意味着我们可以检查实例本身.如果你想要了解更多,可以试着在你模拟的代码下断点,以对这种修补机制的原理获得更好的认识.

陷阱:装饰顺序

当我们在测试方法中使用多个装饰器,其顺序是很重要的,并且很容易混乱.基本上,当装饰器被映射到方法参数时,装饰器的工作顺序是反向的[3].思考这个例子:

  1. ? ?@mock.patch('mymodule.sys')
  2. ? ?@mock.patch('mymodule.os')
  3. ? ?@mock.patch('mymodule.os.path')
  4. ? ?def test_something(self, mock_os_path, mock_sys):
  5. ? ? ? ?pass

注意到我们的参数和装饰器的顺序是反向匹配了吗?这部分是由?Python 的工作方式[4]所导致的.这里是使用多个装饰器的情况下它们执行顺序的伪代码:

  1. patch_sys(patch_os(patch_os_path(test_something)))

因为?sys?补丁位于最外层,所以它最晚执行,使得它成为实际测试方法参数的最后一个参数.请特别注意这一点,并且在运行你的测试用例时,使用调试器来保证正确的参数以正确的顺序注入.

方法 2:创建 Mock 实例

我们可以使用构造函数为?UploadService?提供一个 Mock 实例,而不是模拟特定的实例方法.我更推荐方法 1,因为它更加精确,但在多数情况,方法 2 或许更加有效和必要.让我们再次重构测试用例:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from mymodule import RemovalService, "Failed to not remove the file if not present.")
  4. ? ? ? ?# make the file 'exist'
  5. ? ? ? ?mock_path.isfile.return_value = True
  6. ? ? ? ?reference.rm("any path")
  7. ? ? ? ?mock_os.remove.assert_called_with("any path")
  8. class UploadServiceTestCase(unittest.TestCase):
  9. ? ?def test_upload_complete(self, mock_rm):
  10. ? ? ? ?# build our dependencies
  11. ? ? ? ?mock_removal_service = mock.create_autospec(RemovalService)
  12. ? ? ? ?reference = UploadService(mock_removal_service)
  13. ? ? ? ?# call upload_complete, call `rm`:
  14. ? ? ? ?reference.upload_complete("my uploaded file")
  15. ? ? ? ?# test that it called the rm method
  16. ? ? ? ?mock_removal_service.rm.assert_called_with("my uploaded file")

在这个例子中,我们甚至不需要修补任何功能,只需为?RemovalService?类创建一个 auto-spec,然后将实例注入到我们的?UploadService?以验证功能.

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!