【发布时间】:2018-12-30 04:26:01
【问题描述】:
我正在使用带有 monkeypatch 夹具的 pytest 编写一些测试。按照规则,我从正在使用它们的模块中导入要模拟的类和方法,而不是从源中。
我正在为其编写测试的应用程序是一个使用标准环境的 Google App Engine 应用程序。因此我必须使用 python 2.7,我使用的实际版本是 2.7.15 - pytest 版本是 3.5.0
到目前为止,一切都运行良好,但是在尝试模拟装饰器函数时遇到了问题。
从顶部开始。在一个名为 decorators.py 的 py 文件中,包含所有 auth 装饰器,包括我要模拟的装饰器。有问题的装饰器是一个模块函数,而不是类的一部分。
def user_login_required(handler):
def is_authenticated(self, *args, **kwargs):
u = self.auth.get_user_by_session()
if u.access == '' or u.access is None:
# return the response
self.redirect('/admin', permanent=True)
else:
return handler(self, *args, **kwargs)
return is_authenticated
装饰器应用于网络请求功能。在名为 handlers (handlers.UserDetails) 的文件夹中名为 UserDetails.py 的文件中的基本示例
from decorators import user_login_required
class UserDetailsHandler(BaseHandler):
@user_login_required
def get(self):
# Do web stuff, return html, etc
在一个测试模块中,我正在这样设置测试:
from handlers.UserDetails import user_login_required
@pytest.mark.parametrize('params', get_params, ids=get_ids)
def test_post(self, params, monkeypatch):
monkeypatch.setattr(user_login_required, mock_user_login_required_func)
问题在于monkeypatch 不允许我将单个函数作为目标。它希望目标是一个类,然后是要替换的方法名称,然后是模拟方法....
monkeypatch.setattr(WouldBeClass, "user_login_required", mock_user_login_required_func)
我试图调整代码,看看是否可以通过改变装饰器的导入和使用方式来绕过它:
import decorators
class UserDetailsHandler(BaseHandler):
@decorators.user_login_required
def get(self):
# Do web stuff, return html, etc
然后在测试中我尝试像这样修补函数名称.....
from handlers.UserDetails import decorators
@pytest.mark.parametrize('params', get_params, ids=get_ids)
def test_post(self, params, monkeypatch):
monkeypatch.setattr(decorators, "user_login_required" , mock_user_login_required_func)
虽然这段代码没有抛出任何错误,但当我逐步完成测试时,代码永远不会进入 mock_user_login_required_func。它总是进入现场装饰器。
我做错了什么?这是一个尝试对一般的装饰器进行修补的问题,或者模块中的单独功能可以不被修补吗?
【问题讨论】:
-
修补装饰器的典型问题是,一旦导入模块,装饰器就会运行,修改函数并且永远不会为该函数再次运行。之后修补它没有效果。
-
解释清楚,谢谢克劳斯。看起来我需要直接在装饰器中做一些事情来检测是否正在运行测试。我有一个想法......将进一步调查。
标签: python pytest monkeypatching