在 py.test 中模拟标准库调用

Geo*_*lin 0 python tdd pytest

我正在学习如何使用 py.test 编写测试,但我不知道如何模拟外部调用。

假设我有一个测试代码:

应用程序.py:

import random

def trade_robot(stock, price):
    return ' '.join((random.choice(('buy', 'sell', 'keep')), stock))
Run Code Online (Sandbox Code Playgroud)

我想确保我检查 random.choice 的情况,决定我需要购买(并且我想检查它是否正确连接“购买”情况的字符串)。

我的测试代码应该如下所示:

import pytest
from app import trade_robot
import sys

def test_buy_case():
    # some mock magic here
    assert trade_robot('AAPL', 500) == 'buy AAPL'

if __name__ == "__main__":
    pytest.main("-v %s" % sys.argv[0])
Run Code Online (Sandbox Code Playgroud)

“一些模拟魔法”中应该包含什么才能使该测试每次都通过?谢谢!

ber*_*eal 6

这可以通过库来完成mock,该库从 Python 3.3 开始就包含在标准库中。

首先,使用上下文管理器:

import random
with mock.patch.object(random, 'choice') as m:
    m.return_value = 'buy'
    print random.choice(['anything'])  # prints 'buy' regardless of the arguments
Run Code Online (Sandbox Code Playgroud)

与装饰器相同:

@mock.patch.object(random, 'choice')
def test_buy(m):
    m.return_value = 'buy'
    print random.choice(['anything'])
Run Code Online (Sandbox Code Playgroud)

该库还允许对模拟调用进行断言,并且对于单元测试来说是不可替代的。或者,有些人更喜欢显式依赖倒置,这意味着将函数random.choice作为函数/方法/构造函数参数传递到代码中,并在测试中将其替换为模拟。