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

时间:2019-04-25 16:20:09

标签: django django-rest-framework mocking pytest pytest-django

出于学习的目的,我试图编写一个修补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 个答案:

答案 0 :(得分:1)

修补程序的规则#1:您首先应该猜到的修补程序总是错误的。
修补程序的规则2:请勿在执行过程中查找 IS 的地方进行修补,而在执行过程中查找 Will 的地方进行修补。

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

通过仅导入django.contrib.auth然后修补django.contrib.auth.authenticate,修补程序将其模拟的authenticate潜入django.contrib.auth中。
如果随后使用user == django.contrib.auth.authenticate进行断言,则python将在authenticate中查找django.contrib.auth并找到模拟对象。

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