1.问题
前面我们讨论了pytest-mock
,给模块mock的使用方法。当时还列举了两个问题,如何给对象的属性进行mock,以及如何同一个地方进行mock,避免每个测试用例单独mock,我们现在来看看这两个问题。
2.方案
2.1.给对象属性mock
首先我们看下为何会有对象mock的问题。python
中不少代码,开发的时候不会指明类型,到了实际执行的时候才会知道用什么类型,因此不能使用import
,所以用前面说的对模块mock就行不通了。
我们来构造这样一个例子。chaos
模块中,继续定义一个Person
类。代码如下:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
self.car = None
def go_tools_name(self):
# 获取交通工具的名称
return self.car.name
...
Person
中,没有提供car
的赋值,go_tools_name
我们如何测试?这个时候就得要对对象进行mock了。测试代码如下:
class MockerCar:
def __init__(self, name):
self.name = name
def test_person_01(mocker):
person = Person('chaos', 100)
assert person.name == 'chaos'
assert person.age == 100
car = MockerCar('bmw')
mocker.patch.object(
person, "car", car)
assert person.car == car
assert person.go_tools_name() == 'bmw'
我们使用mocker.patch.object
偷偷给person
这个对象塞进一辆车,这样就可以对go_tools_name
方法进行测试了。
2.2.初始化mocker
测试用例非常多的时候,避免在每个用例中进行mock,使用很不方便。我们可以利用pytest
的夹具fixture
,当然也可以把测试用例写成类。这里主要介绍下夹具下的mock,测试代码如下:
import pytest
from pytest_mock import mocker
import chaos
def mock_func(s):
if s == '~' :
return 'home/chaos'
else:
return '/usr/lib'
@pytest.fixture()
def myfix(mocker):
mocker.patch('chaos.expanduser', return_value=mock_func)
def test_chaos_01(myfix):
ret = chaos.get_pipconf_filename('~')
assert ret == '/home/chaos/.pip/pip.conf'
def test_chaos_02(myfix):
ret = chaos.get_pipconf_filename('^_^')
assert ret == '/usr/lib'
这样就大功告成了。
3.讨论
关于python的mock
使用特别多,网上大多数没有根据实际使用情况进行说明,所以看了也感觉云里雾里,看了之后还是不会用。这里列举了两篇,只是mock的一部分,但例子是真实使用过程比较常见的,至少可以启动测试了。