half-life
@half-life

Как пофиксить проваливающийся тест (Django Rest Framework)?

Всем бобра. Объясните в каком месте я не прав? Последний тест валиться с ошибкой
AssertionError: Expected view AuthorViewSet to be called with a URL keyword argument named "id". 
Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
test_viewsets.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.test import TestCase
from rest_framework.reverse import reverse_lazy
from rest_framework.test import APIRequestFactory

from src.apps.book.factories import AuthorFactory, BookFactory
from src.apps.book.views import AuthorViewSet, BookViewSet


class BookViewSetTestCase(TestCase):
    def setUp(self):
        super(BookSerializerTestCase, self).setUp()
        self.authors = AuthorFactory.create_batch(size=2)
        self.books = BookFactory.create_batch(size=2, author=self.authors[0])
        self.factory = APIRequestFactory()

    def tearDown(self):
        super(BookSerializerTestCase, self).tearDown()
        AuthorFactory.reset_sequence()
        BookFactory.reset_sequence()

    def test_author_list_view_set(self):
        view = AuthorViewSet.as_view({'get': 'list'})
        request = self.factory.get(reverse_lazy('author-list'))
        response = view(request)
        response.render()
        self.assertEqual(response.status_code, 200)

    def test_author_retrieve_view_set(self):
        view = AuthorViewSet.as_view({'get': 'retrieve'})
        request = self.factory.get(reverse_lazy('author-detail', args=(self.authors[0].pk,)))
        response = view(request)
        response.render()
        self.assertEqual(response.status_code, 200)



views.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from rest_framework import viewsets
from rest_framework_extensions.mixins import DetailSerializerMixin

from src.apps.book.models import AuthorModel, BookModel
from src.apps.book.permissions import IsAccountAdminOrReadOnly
from src.apps.book.serializers import AuthorListSerializer, AuthorRetrieveSerializer, BookSerializer


class AuthorViewSet(DetailSerializerMixin, viewsets.ModelViewSet):
    model = AuthorModel
    queryset = AuthorModel.objects.prefetch_related('books').all()
    serializer_class = AuthorListSerializer
    serializer_detail_class = AuthorRetrieveSerializer
    permission_classes = [
        IsAccountAdminOrReadOnly
    ]
    lookup_field = 'id'


class BookViewSet(viewsets.ModelViewSet):
    model = BookModel
    queryset = BookModel.objects.select_related('author').all()
    serializer_class = BookSerializer
    permission_classes = [
        IsAccountAdminOrReadOnly
    ]
    lookup_field = 'isbn'

  • Вопрос задан
  • 1171 просмотр
Решения вопроса 1
half-life
@half-life Автор вопроса
Надо было в вызове вьюхи передать значение поля id для автора и isbn для книги. Вот так:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from rest_framework.reverse import reverse_lazy
from rest_framework.test import APIRequestFactory, APITestCase

from src.apps.book.factories import AuthorFactory, BookFactory
from src.apps.book.views import AuthorViewSet, BookViewSet


class BookSerializerTestCase(APITestCase):
    def setUp(self):
        super(BookSerializerTestCase, self).setUp()
        self.authors = AuthorFactory.create_batch(size=2)
        self.books = BookFactory.create_batch(size=2, author=self.authors[0])
        self.factory = APIRequestFactory()

    def tearDown(self):
        super(BookSerializerTestCase, self).tearDown()
        AuthorFactory.reset_sequence()
        BookFactory.reset_sequence()

    def test_author_list_view_set(self):
        view = AuthorViewSet.as_view({'get': 'list'})
        request = self.factory.get(reverse_lazy('author-list'))
        response = view(request)
        self.assertEqual(response.status_code, 200)

    def test_author_retrieve_view_set(self):
        view = AuthorViewSet.as_view({'get': 'retrieve'})
        request = self.factory.get(reverse_lazy('author-detail', args=(self.authors[0].pk,)))
        response = view(request, id=self.authors[0].pk)
        self.assertEqual(response.status_code, 200)

    def test_book_list_view_set(self):
        view = BookViewSet.as_view({'get': 'list'})
        request = self.factory.get(reverse_lazy('book-list'))
        response = view(request)
        self.assertEqual(response.status_code, 200)

    def test_book_retrieve_view_set(self):
        view = BookViewSet.as_view({'get': 'retrieve'})
        request = self.factory.get(reverse_lazy('book-detail', args=(self.books[0].isbn,)))
        response = view(request, isbn=self.books[0].isbn)
        self.assertEqual(response.status_code, 200)
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
werevolff
@werevolff
from rest_framework.test import APITestCase

class AccountTests(APITestCase):
def test_endpoint(self):
url = reverse('some_url')
response = self.client.get(url)

Сорри что не отформатировал: пишу со смарта. Насколько я понимаю, приведённый мной код вылетит с ошибкой no reverse match если не передать id. И, как я понимаю, в вашем примере именно id не хватает для вьюхи. Однако, я не видел, чтобы вьюху вот так просто дёргали за as_view. Эта ф-ия возвращает, насколько помню, другую ф-ию (dispatch?), которой передаётся request и пачка кваргов (если заявлено). Так что правильно тут либо обращаться по reverse, либо делать MyView.as_view()(request, *args, **kwargs).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы