pytest - 如何修补方法以避免数据库调用



为了学习,我正在尝试编写一个测试来修补 Django 的 authenticate 函数,以避免不得不访问数据库。我写的代码不起作用,我不明白为什么。我已经在网上搜索过,但发现我读到的很多内容都令人困惑。任何帮助将不胜感激。

我正在使用Django,DRF,pytest,pytest-django和pytest-mock。

from django.contrib.auth import authenticate
from rest_framework.test import APIRequestFactory
def test_authenticate(mocker, user_factory):
    user = user_factory.build()
    mocker.patch('django.contrib.auth.authenticate', return_value=user)
    factory = APIRequestFactory()
    request = factory.get('/')
    data = {
        'username': user.email,
        'password': 'testpassword',
    }
    assert user == authenticate(request=request, **data)

在上面的代码中,user_factory来自conftest.py,我们可以假设它按预期工作。

我收到的错误是:

E       Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.        

同样,我想避免为数据库访问标记测试。相反,我希望能够模拟authenticate并控制其返回值。

修补规则 #1:你首先猜测你应该打补丁总是错误的。
修补规则#2:不要在某物所在的地方打补丁,而是在执行期间将查找某物的地方打补丁。

您导入了authenticate并将其作为authenticate添加到命名空间中。修补补丁程序时,django.contrib.auth.authenticate导入命名空间,然后对其进行模拟。稍后您调用 authenticate ,您一开始导入的原始版本 - 而不是补丁程序为您导入的模拟版本。

通过仅导入django.contrib.auth然后修补django.contrib.auth.authenticate,补丁程序在其模拟authenticate中"潜入"django.contrib.auth
如果你然后用user == django.contrib.auth.authenticate做断言,python 将在django.contrib.auth中寻找authenticate,并找到模拟。

经典补丁之谜:https://docs.python.org/3/library/unittest.mock.html#where-to-patch

最新更新