N
N
Nick V2016-08-01 20:02:08
Test Driven Development
Nick V, 2016-08-01 20:02:08

How to fix a failing test (Django Rest Framework)?

Beaver everyone. Explain where I'm wrong? Last test fails

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'

Answer the question

In order to leave comments, you need to log in

2 answer(s)
N
Nick V, 2016-08-01
@half-life

It was necessary to transfer the value of the id field for the author and isbn for the book in the view call. Like this:

# -*- 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)

W
werevolff, 2016-08-01
@werevolff

from rest_framework.test import APITestCase
class AccountTests(APITestCase):
def test_endpoint(self):
url = reverse('some_url') response
= self.client.get(url)
As far as I understand, the code I provided will crash with a no reverse match error if you do not pass id. And, as I understand it, in your example, it is the id that is missing for the view. However, I have not seen that the view was simply pulled by as_view like that. This function returns, as far as I remember, another function (dispatch?), to which request and a pack of quargs (if declared) are passed. So it's correct to either reverse here, or do MyView.as_view()(request, *args, **kwargs).

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question