如何在具有模拟装饰器的测试上使用pytest capsys?

时间:2018-08-28 15:00:19

标签: python testing mocking pytest python-decorators

我一直在尝试找到一种同时使用模拟装饰器和pytest capsys的方法,但是我找不到正确的方法来实现它。

import pytest
import requests_mock


@requests_mock.mock()
def test_with_mock(m):
    pass

def test_with_capsys(capsys):
    pass


# how to write a test that works with both?

1 个答案:

答案 0 :(得分:2)

request-mock's docs中所述:

  

pytest有其自己的注册和加载自定义装置的方法。 requests-mock提供了向pytest注册的外部设备,因此只需将其指定为参数即可使用。无需导入requests-mock,只需安装并指定参数requests_mock

     

然后,灯具提供与requests_mock.Mocker相同的界面,使您可以按预期使用requests-mock

>>> import pytest
>>> import requests

>>> def test_url(requests_mock):
...     requests_mock.get('http://test.com', text='data')
...     assert 'data' == requests.get('http://test.com').text
...

因此,只需使用requests_mock固定装置而不是装饰器即可:

def test_with_mock_and_capsys(requests_mock, capsys):
    pass

背景

pytest不能与将位置参数添加到测试函数的函数装饰器一起使用。 pytest考虑所有符合条件的参数

  • 没有像实例或类方法那样绑定到实例或类型;
  • 没有默认值;
  • 没有与functools.partial绑定;
  • 没有用unittest.mock的模拟代替

替换为fixture值,如果找不到适合任何参数的fixture,它将失败。这样的东西

import functools
import pytest


def deco(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        args += ('spam',)
        return func(*args, **kwargs)
    return wrapper


@deco
def test_spam(spam_arg):
    assert True

将失败,而这正是requests-mock所做的。一种解决方法是通过关键字args传递模拟程序:

import pytest
import requests_mock


@requests_mock.Mocker(kw='m')
def test_with_mock_and_fixtures(capsys, **kwargs):
    m = kwargs['m']
    ...

但是由于requests-mock已经提供了灯具,为什么还要麻烦使用装饰器?