@hainingwyx
2018-12-05T18:37:20.000000Z
字数 3469
阅读 1271
python
测试
Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代掉指定的Python对象,以达到模拟对象的行为。
Mock对象是mock模块中最重要的概念。Mock对象就是mock模块中的一个类的实例,这个类的实例可以用来替换其他的Python对象,来达到模拟的效果。
客户端代码client.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
def send_request(url):
r = requests.get(url)
return r.status_code
def visit_ustack():
return send_request('http://www.ustack.com')
mock对象在单元测试中分别测试访问正常和访问不正常的情况test.py。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import mock
import client
class TestClient(unittest.TestCase):
def test_success_request(self):
success_send = mock.Mock(return_value='200')
client.send_request = success_send
self.assertEqual(client.visit_ustack(), '200')
def test_fail_request(self):
fail_send = mock.Mock(return_value='404')
client.send_request = fail_send
self.assertEqual(client.visit_ustack(), '404')
Mock类的定义如下:
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
patch
和patch.object
都会返回_path实例,返回的实例既可以作为函数的装饰器,也可以作为类的装饰器,也可以作为上下文管理器。
lass TestClient(unittest.TestCase):
def test_success_request(self):
status_code = '200'
success_send = mock.Mock(return_value=status_code)
with mock.patch('client.send_request', success_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code)
def test_fail_request(self):
status_code = '404'
fail_send = mock.Mock(return_value=status_code)
with mock.patch('client.send_request', fail_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code)
如果使用patch.object
def test_fail_request(self):
status_code = '404'
fail_send = mock.Mock(return_value=status_code)
with mock.patch.object(client, 'send_request', fail_send):
from client import visit_ustack
self.assertEqual(visit_ustack(), status_code)
替换掉一个对象的指定名称的属性,用法和setattr类似。
装饰器
mock.patch
装饰器来用 mock对象替client.send_request。然后,我们将它作为一个参数success_send
插入到我们的测试代码中。在这个测试的上下文中,任何对send_requesty
的调用都会被重定向到success_send
对象。
@mock.patch('client.send_request')
def test_success_req(self, success_send):
success_send.return_value = '200'
self.assertEqual(client.visit_ustack(), '200')
@mock.patch.object(client, 'send_request')
def test_decorator2_req(self, success_send):
success_send.return_value = '200'
self.assertEqual(client.visit_ustack(), '200')
side_effect
可以利用side_effect测试多个返回值
def test_many_req(self):
client.send_request = mock.Mock(side_effect=['200', '404'])
self.assertEqual(client.visit_ustack(), '200')
self.assertEqual(client.visit_ustack(), '404')
异常
测试代码抛出异常
def test_exception1_req(self):
exception_send = mock.Mock(side_effect=TypeError('integer type'))
client.send_request = exception_send
self.assertRaises(TypeError, lambda:client.visit_ustack())
def test_exception2_req(self):
exception_send = mock.Mock(side_effect=TypeError('integer type'))
client.send_request = exception_send
with self.assertRaises(TypeError) as context:
client.visit_ustack()
self.assertTrue('integer type' in context.exception)
def test_exception3_req(self):
exception_send = mock.Mock(side_effect=TypeError('integer type'))
client.send_request = exception_send
self.assertRaises(TypeError, client.visit_ustack)
链式调用
# 返回数据库中所有指定name的人员,并按age排序
def get_person(name):
return Person.objects.filter(name=name).order_by('age')
@patch('your.package.module.Person.objects.filter')
def test_should_get_person(self, mock_filter):
# 先得到一个filter的Mock对象,再在return_value中设置一个Mock对象,此时不需要自己再创建
mock_filter.return_value.order_by.return_value = None
self.assertIsNone(get_person())