py.test在自定义funcargs中使用monkeypatch

4 投票
2 回答
2538 浏览
提问于 2025-04-16 17:44

我在使用py.test这个工具,特别喜欢用funcarg的方法把对象注入到测试函数里。在我的测试中,我需要使用Mock对象,因为我有很多外部依赖。为了替换某些属性,我会用monkeypatch来处理这些Mock对象。

我遇到的问题是,很多测试都会用到同一个funcarg,并且总是需要替换相同的属性。到目前为止,我在每个测试函数里都要替换这些属性。

有没有办法在我的funcarg函数里使用monkeypatch,这样就能把这些重复的代码从每个测试中去掉呢?

import sys
import pytest
from mock import Mock


#----------------------------------------------------------------------
def pytest_funcarg__api(request):
    """"""
    api = myclass()
    #do some initialisation...
    return api


#----------------------------------------------------------------------
def test_bla1(monkeypatch, api):
    """"""
    monkeypatch.setattr(api,"get_external_stuff",Mock())
    monkeypatch.setattr(api,"morestuff",Mock())

    api.do_something1()
    assert not api.a

#----------------------------------------------------------------------
def test_bla2(monkeypatch, api):
    """"""
    monkeypatch.setattr(api,"get_external_stuff",Mock())
    monkeypatch.setattr(api,"morestuff",Mock())

    api.do_something2()
    assert api.b


if __name__=='__main__':
    pytest.main(args=["-v",sys.argv[0]])

2 个回答

2

这个方法应该有效:

def pytest_funcarg__api(request):
    """"""
    api = myclass()
    #do some initialisation...
    mp_plugin = request.config.pluginmanager.getplugin("monkeypatch")
    monkeypatch = mp_plugin.pytest_funcarg__monkeypatch(request)
    monkeypatch.setattr(api,"get_external_stuff",Mock())
    monkeypatch.setattr(api,"morestuff",Mock())
    return api

这里的窍门有两个:

  1. 我们通过 config.pluginmanager 获取 monkeypatch 插件。
  2. 我们让 monkeypatch 插件误以为是被 py.test 的依赖注入代码调用,方法是用我们自己的请求对象来调用它的 pytest_funcarg__monkeypatch() 函数接口。
5

你可以使用文档中提到的 getfuncargvalue 函数,来在一个函数的参数工厂中内部使用另一个函数的参数。

def pytest_funcarg__api(request):
    api = myclass()
    #do some initialisation...
    mp = request.getfuncargvalue("monkeypatch")
    mp.setattr(api,"get_external_stuff", Mock())
    mp.setattr(api,"morestuff", Mock())
    return api

撰写回答