Python学习:如何试用pytest-mock(2)

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的一部分,但例子是真实使用过程比较常见的,至少可以启动测试了。

Python学习:如何试用pytest-mock(1)

你可能感兴趣的:(Python学习:如何试用pytest-mock(2))