Pytest使用django_db和rest框架

时间:2018-05-17 00:32:48

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

我正在尝试使用django_db进行简单的测试以对抗真实django rest framework而不是测试数据库。

基本测试设置:

import pytest
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient

@pytest.mark.django_db
def test_airport_list_real():
    client = APIClient()
    response = client.get(reverse('query_flight:airports-list'))
    assert response.status_code == 200
    assert len(response.json()) > 0

运行此测试我得到:

___________________________ test_airport_list_real ____________________________

    @pytest.mark.django_db
    def test_airport_list_real():
        client = APIClient()
        response = client.get(reverse('query_flight:airports-list'))
        assert response.status_code == 200
>       assert len(response.json()) > 0
E       assert 0 > 0
E        +  where 0 = len([])
E        +    where [] = functools.partial(<bound method Client._parse_json of <rest_framework.test.APIClient object at 0x000001A0AB793908>>, <Response status_code=200, "application/json">)()
E        +      where functools.partial(<bound method Client._parse_json of <rest_framework.test.APIClient object at 0x000001A0AB793908>>, <Response status_code=200, "application/json">) = <Response status_code=200, "application/json">.json

query_flight\tests\query_flight\test_api.py:60: AssertionError

当使用pipenv run python manage.py shell在shell中运行时,我得到了预期的结果:     在[1]中:从django.urls导入反向

In [2]: from rest_framework.test import APIClient

In [3]: client = APIClient()

In [4]: response = client.get(reverse('query_flight:airports-list'))

In [5]: len(response.json())
Out[5]: 100

使用以下包:

pytest-django==3.2.1
pytest [required: >=2.9, installed: 3.5.1]
djangorestframework==3.8.2
django [required: >=1.8, installed: 2.0.5]

有没有让pytest以这种方式访问​​真实数据库?

2 个答案:

答案 0 :(得分:1)

你有几个选择。默认情况下,使用Django的TestClient或DRF的APIClient将使用测试数据库和应用程序的本地版本。要连接到您的实时API,您可以使用Requests之类的库来执行HTTP请求,然后在测试中使用这些响应:

import requests

@pytest.mark.django_db
def test_airport_list_real():
    response = requests.get('https://yourliveapi.biz')
    assert response.status_code == 200
    assert len(response.json()) > 0

要特别注意在该实时数据库上执行专门的只读测试。

答案 1 :(得分:1)

django_db标记仅负责为测试数据库提供标记测试的连接。传递给pytest-django的django设置完全负责选择测试运行中使用的数据库。

您可以通过定义pytest-django fixture来覆盖django_db_setup中的数据库使用情况。如果您还没有在项目根目录中创建conftest.py文件,请覆盖数据库配置:

# conftest.py
import pytest

@pytest.fixture(scope='session')
def django_db_setup():
    settings.DATABASES['default'] = {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'path/to/dbfile.sqlite3',
    }

但是,您不应该在测试中使用真实数据库。转储当前的数据库以获取测试数据的快照(python manage.py dumpdata > testdata.json)并将其加载到空的测试数据库中,以便在测试运行之前填充它:

# conftest.py
import pytest
from django.core.management import call_command

@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        call_command('loaddata', 'testdata.json')

现在,在运行测试时,您可能无法破坏真正的数据库;实际数据库中的任何未来更改都不会导致测试失败(例如,删除某些数据时),并且每次测试运行时始终都有确定性状态。如果您需要一些额外的测试数据,请将它以JSON格式添加到testdata.json,您的测试就可以了。

来源:Examples in pytest-django docs