0

I'm writing some tests for my Django Rest Framework and trying to keep them as simple as possible. Before, I was creating objects using factory boy in order to have saved objects available for GET requests.

Why are my POST requests in the tests not creating an actual object in my test database? Everything works fine using the actual API, but I can't get the POST in the tests to save the object to make it available for GET requests. Is there something I'm missing?

from rest_framework import status
from rest_framework.test import APITestCase

# from .factories import InterestFactory


class APITestMixin(object):
    """
    mixin to perform the default API Test functionality
    """
    api_root = '/v1/'
    model_url = ''
    data = {}

    def get_endpoint(self):
        """
        return the API endpoint
        """
        url = self.api_root + self.model_url
        return url

    def test_create_object(self):
        """
        create a new object
        """
        response = self.client.post(self.get_endpoint(), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data, self.data)
        # this passes the test and the response says the object was created

    def test_get_objects(self):
        """
        get a list of objects
        """
        response = self.client.get(self.get_endpoint())
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, self.data)
        # this test fails and says the response is empty [] with no objects


class InterestTests(APITestCase, APITestMixin):
    def setUp(self):
        self.model_url = 'interests/'
        self.data = {
            'id': 1,
            'name': 'hiking',
        }

        # self.interest = InterestFactory.create(name='travel')
        """
        if I create the object with factory boy, the object is 
        there. But I don't want to have to do this - I want to use
        the data that was created in the POST request
        """

You can see the couple lines of commented out code which are the object that I need to create through factory boy because the object does not get created and saved (although the create test does pass and say the object is created).

I didn't post any of the model, serializer or viewsets code because the actual API works, this is a question specific to the test.

1
  • The database content is cleared between each test method. You need a dedicated helper method for creating objects and reuse it in each test case. Commented Mar 26, 2015 at 19:36

1 Answer 1

5

First of all, Django TestCase (APITestCase's base class) encloses the test code in a database transaction that is rolled back at the end of the test (refer). That's why test_get_objects cannot see objects which created in test_create_object

Then, from (Django Testing Docs)

Having tests altering each others data, or having tests that depend on another test altering data are inherently fragile.

The first reason came into my mind is that you cannot rely on the execution order of tests. For now, the order within a TestCase seems to be alphabetical. test_create_object just happened to be executed before test_get_objects. If you change the method name to test_z_create_object, test_get_objects will go first. So better to make each test independent

Solution for your case, if you anyway don't want database reset after each test, use APISimpleTestCase

More recommended, group tests. E.g., rename test_create_object, test_get_objects to subtest_create_object, subtest_get_objects. Then create another test method to invoke the two tests as needed

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Yeah that all makes sense, in other scenarios I have invoked the create test within the get object test and found that that works. I thought the database was cleared at the end of each TestCase class, not at the end of each function.
I wish I could up vote this answer more. Thank you, now I understand!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.