[关闭]
@hainingwyx 2018-12-05T10:37:20.000000Z 字数 3469 阅读 569

mock

python 测试


Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代掉指定的Python对象,以达到模拟对象的行为。

Mock对象是mock模块中最重要的概念。Mock对象就是mock模块中的一个类的实例,这个类的实例可以用来替换其他的Python对象,来达到模拟的效果。

简单使用

客户端代码client.py

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import requests
  4. def send_request(url):
  5. r = requests.get(url)
  6. return r.status_code
  7. def visit_ustack():
  8. return send_request('http://www.ustack.com')

mock对象在单元测试中分别测试访问正常和访问不正常的情况test.py。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import unittest
  4. import mock
  5. import client
  6. class TestClient(unittest.TestCase):
  7. def test_success_request(self):
  8. success_send = mock.Mock(return_value='200')
  9. client.send_request = success_send
  10. self.assertEqual(client.visit_ustack(), '200')
  11. def test_fail_request(self):
  12. fail_send = mock.Mock(return_value='404')
  13. client.send_request = fail_send
  14. self.assertEqual(client.visit_ustack(), '404')

深入了解

Mock类的定义如下:

  1. class Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs)

name: 命名一个mock对象。

return_value: 指定一个值(或者对象),返回return_value指定的值。

side_effect:指向一个可调用对象,一般是函数。当mock对象被调用时,如果该函数返回不是DEFAULT时,那么以该函数的返回值作为mock对象调用的返回值。

patch
patchpatch.object都会返回_path实例,返回的实例既可以作为函数的装饰器,也可以作为类的装饰器,也可以作为上下文管理器。

  1. lass TestClient(unittest.TestCase):
  2. def test_success_request(self):
  3. status_code = '200'
  4. success_send = mock.Mock(return_value=status_code)
  5. with mock.patch('client.send_request', success_send):
  6. from client import visit_ustack
  7. self.assertEqual(visit_ustack(), status_code)
  8. def test_fail_request(self):
  9. status_code = '404'
  10. fail_send = mock.Mock(return_value=status_code)
  11. with mock.patch('client.send_request', fail_send):
  12. from client import visit_ustack
  13. self.assertEqual(visit_ustack(), status_code)

如果使用patch.object

  1. def test_fail_request(self):
  2. status_code = '404'
  3. fail_send = mock.Mock(return_value=status_code)
  4. with mock.patch.object(client, 'send_request', fail_send):
  5. from client import visit_ustack
  6. self.assertEqual(visit_ustack(), status_code)

替换掉一个对象的指定名称的属性,用法和setattr类似。

装饰器
mock.patch装饰器来用 mock对象替client.send_request。然后,我们将它作为一个参数success_send插入到我们的测试代码中。在这个测试的上下文中,任何对send_requesty的调用都会被重定向到success_send对象。

  1. @mock.patch('client.send_request')
  2. def test_success_req(self, success_send):
  3. success_send.return_value = '200'
  4. self.assertEqual(client.visit_ustack(), '200')
  5. @mock.patch.object(client, 'send_request')
  6. def test_decorator2_req(self, success_send):
  7. success_send.return_value = '200'
  8. self.assertEqual(client.visit_ustack(), '200')

side_effect
可以利用side_effect测试多个返回值

  1. def test_many_req(self):
  2. client.send_request = mock.Mock(side_effect=['200', '404'])
  3. self.assertEqual(client.visit_ustack(), '200')
  4. self.assertEqual(client.visit_ustack(), '404')

异常
测试代码抛出异常

  1. def test_exception1_req(self):
  2. exception_send = mock.Mock(side_effect=TypeError('integer type'))
  3. client.send_request = exception_send
  4. self.assertRaises(TypeError, lambda:client.visit_ustack())
  5. def test_exception2_req(self):
  6. exception_send = mock.Mock(side_effect=TypeError('integer type'))
  7. client.send_request = exception_send
  8. with self.assertRaises(TypeError) as context:
  9. client.visit_ustack()
  10. self.assertTrue('integer type' in context.exception)
  11. def test_exception3_req(self):
  12. exception_send = mock.Mock(side_effect=TypeError('integer type'))
  13. client.send_request = exception_send
  14. self.assertRaises(TypeError, client.visit_ustack)

链式调用

  1. # 返回数据库中所有指定name的人员,并按age排序
  2. def get_person(name):
  3. return Person.objects.filter(name=name).order_by('age')
  1. @patch('your.package.module.Person.objects.filter')
  2. def test_should_get_person(self, mock_filter):
  3. # 先得到一个filter的Mock对象,再在return_value中设置一个Mock对象,此时不需要自己再创建
  4. mock_filter.return_value.order_by.return_value = None
  5. self.assertIsNone(get_person())

参考文献

https://segmentfault.com/a/1190000002965620

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注