sol*_*977 7 python monkeypatching pytest
我正在使用 pytest 和 Monkeypatch 固定装置编写一些测试。按照规则,我导入类和方法以从它们正在使用的模块而不是源代码中模拟出来。
我正在为其编写测试的应用程序是一个使用标准环境的 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
Run Code Online (Sandbox Code Playgroud)
该装饰器应用于Web请求功能。名为 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
Run Code Online (Sandbox Code Playgroud)
在测试模块中,我设置测试如下:
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)
Run Code Online (Sandbox Code Playgroud)
问题在于,monkeypatch 不允许我将单个函数作为目标。它希望目标是一个类,后面是要替换的方法名称,然后是模拟方法......
monkeypatch.setattr(WouldBeClass, "user_login_required", mock_user_login_required_func)
Run Code Online (Sandbox Code Playgroud)
我尝试调整代码,看看是否可以通过更改装饰器的导入和使用方式来绕过它,如下所示:
import decorators
class UserDetailsHandler(BaseHandler):
@decorators.user_login_required
def get(self):
# Do web stuff, return html, etc
Run Code Online (Sandbox Code Playgroud)
然后在测试中我尝试像这样修补函数名称......
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)
Run Code Online (Sandbox Code Playgroud)
尽管此代码不会引发任何错误,但当我单步执行测试时,代码永远不会进入mock_user_login_required_func。它总是进入现场装饰器。
我究竟做错了什么?这是尝试对装饰器进行一般性修补的问题,还是模块中的单独函数无法修补?
看起来这里的快速答案就是简单地移动您的处理程序导入,以便它在补丁之后发生。装饰器和被装饰的函数必须位于单独的模块中,以便 python 在您修补它之前 \xe2\x80\x99 不会执行装饰器。
\n\nfrom decorators import user_login_required\n\n@pytest.mark.parametrize(\'params\', get_params, ids=get_ids)\ndef test_post(self, params, monkeypatch):\n\n monkeypatch.setattr(decorators, "user_login_required" , mock_user_login_required_func)\n from handlers.UserDetails import UserDetailsHandler\nRun Code Online (Sandbox Code Playgroud)\n\n您可能会发现使用内置的 unittest.mock 模块中的 patch 函数可以更轻松地完成此任务。
\n