Pytest 中 patch 的顺序

今天在实习的公司编写测试文件,测试总是不通过,在花了一天的时间才将范围缩小到了测试使用的模块中,进而缩小到了 patch 的声明顺序上。下面举例子说明。

首先,我们有一个 ppod.py 的文件,运行一个简单的 Flask 框架下的小网页:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"""PPOD: Pytest Patch Order Demo."""

import json
import random

from flask import Flask
from mock import mock


def funcA():
    return 'A'


def funcB():
    return 'B'


app = Flask(__name__)


@app.route("/")
def index():
    a = funcA()
    b = funcB()
    return json.dumps(
        {
            "info": "hello {}{}".format(a, b)
        }
    )


if __name__ == '__main__':
    app.run()

然后,我们针对这个文件,编写一个简单的测试文件 test_ppod.py

import json

import pytest
from mock import Mock, patch

import ppod as main

app = main.app
client = app.test_client()


class Test_index:
    @patch('ppod.funcA')
    @patch('ppod.funcB')
    def test_index_one(self, mock_a, mock_b):
        mock_a.return_value = 'a'
        mock_b.return_value = 'b'
        rv = client.get('/')
        data_return = json.loads(rv.data)
        print(data_return)
        assert data_return['info'] == 'hello ba'

    @patch('ppod.funcB')
    @patch('ppod.funcA')
    def test_index_two(self, mock_a, mock_b):
        mock_a.return_value = 'a'
        mock_b.return_value = 'b'
        rv = client.get('/')
        data_return = json.loads(rv.data)
        print(data_return['info'])
        assert data_return['info'] == 'hello ab'

终端中运行 pytest test_ppod.py,编译通过了。

请注意测试的第一个函数,如果 funcA, funcB 对应的是 mock_a, mock_b 的话,为了使检查通过,我们应当写成 assert data_return['info'] == 'hello ab',可是事实上,funcA, funcB 对应的是 mock_b, mock_a

那么为什么会这样子呢?在官方文档 unittest.mock — mock object library — Python 3.7.3 documentation 有这么一段话:

Note
 
When you nest patch decorators the mocks are passed in to the decorated function in the same order they applied (the normal Python order that decorators are applied). This means from the bottom up, so in the example above the mock for module.ClassName1 is passed in first.
 
With patch() it matters that you patch objects in the namespace where they are looked up. This is normally straightforward, but for a quick guide read where to patch .

注意 from the bottom up,看来 patch 的声明有点像堆栈结构,先进后出。

Comments
Write a Comment