0

I am doing unit testing of the rest Apis. I am using django rest framework. Apis are saving data into and getting data from the database. Both of the operations are not working or if it is working i am not able to see that in the databases. Apis are also using django-fsm, because of which i need same data from the db for the other tests. Tests depends on previous tests due to django-fsm. There is always state changing with the api. But now i am not able to see any data in database during test runs. Don't know where it is saving the data or in which database.

Below is my test settings:-

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': join(PROJECT_ROOT, 'run', 'db_for_testing.sqlite3'),
    'TEST': {
        'NAME': 'test_db_for_testing',
    },
 },
}

below is my api:-

class DummyView(CreateAPIView):
    def post(self, request, *args, **kwargs):
        data = request.data.copy()
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        order = self.model(book=serializer.data.get('book'))
        order.save()
        data = {
        'status_code': 200,
        'message': 'successfully.'
        }
        return Response(data, status=status.HTTP_200_OK)

As my tests depends on the previous test saving the data to db, so the other tests also fails. I am using APITestCase of rest_framework. Help guys. thanks in advance.

4 Answers 4

1

If I'm understanding your question correctly, Django "clear" database after each test (either rolling back or truncating.) So you need to write your tests accordingly.

See: https://docs.djangoproject.com/en/1.10/topics/testing/tools/#transactiontestcase

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

4 Comments

So how will i force it to not clear the db after each test? Because I need same data for each test. because of the finite state machine
write them in one test?
okay. thanks. But there must be a way to force it to not truncate the db.
per stackoverflow.com/questions/30504031/… I think you can use Python's unittest.TestCase
1

TL;DR - Solution: Use SimpleTestCase - See example below


Explanation

The thing is that the recommended test classes provided by Django for tests involving database queries, TransactionTestCase and the subclass TestCase, wraps every test in a transaction to speed up the process of resetting the database after each test. Source: Django TransactionTestCase docs

It is possible to avoid this behaviour by using SimpleTestCase which is the parent class of TransactionTestCase. You then have to specify explicitly that you want to allow database queries by setting allow_database_queries to True-

Also note that you are then responsible for any cleaning that needs to be done after the test. You can do that by overriding the tearDownClass class method. Similarly there's a setUpClass class method for any initialization prior to running the test. Remember to call the super methods. See full details in the docs


Example

from django.test import SimpleTestCase

class MyTestCase(SimpleTestCase):
    allow_database_queries = True

    @classmethod
    def setUpClass(cls):
        # Do your pre test initialization here.
        super(MyTestCase, cls).setUpClass()

    @classmethod
    def tearDownClass(cls):
        # Do your post test clean uphere.
        super(MyTestCase, cls).tearDownClass()

    def test_add_data_through_api(self):
        # Add 'dat data
        ...

    def test_work_with_data_from_previous_test(self):
        # Work 'dat data
        ...

Comments

1

Here my three tests are dependent with previous one. If I run them as separate test the previous test data deleted and later one failed for lost of that data.

So I make them in two different functions both are not test function. Finally call the dependent functions from one test function.

class test_profile(APITestCase):
    def setUp(self):
        super_user = default_service.create_super_user()
        self.application = default_service.create_oath2_application(super_user.id)
        self.content_type = "application/x-www-form-urlencoded"
        self.username = "[email protected]"
        self.password = "pass123"

    def create_profile(self):
        url = reverse('EmailSignUp')
        body = {
            "email": self.username,
            "password": self.password,
            "fullname": "Mamun Hasan"
        }
        response = self.client.post(url, body, CONTENT_TYPE=self.content_type)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = (json.loads(response.content))['data']
        # print("Profile", data)
        self.assertEqual(data['username'], self.username)
        self.assertEqual(data['fullname'], data['fullname'])

    def get_access_token(self):
        url = reverse('oauth2_provider:token')
        body = {
            "username": self.username,
            "password": self.password,
            "grant_type": self.application.authorization_grant_type,
            "client_id": self.application.client_id,
            "client_secret": self.application.client_secret,
        }
        response = self.client.post(url, body, CONTENT_TYPE=self.content_type)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = (json.loads(response.content))
        # print("AccessToken", data)
        self.assertEqual(data['token_type'], 'Bearer')
        return data

    def get_profile(self, oath2_token):
        url = reverse('GetProfile')
        authorization = oath2_token["token_type"] + ' ' + oath2_token["access_token"]
        response = self.client.get(url, CONTENT_TYPE=self.content_type, HTTP_AUTHORIZATION=authorization)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = (json.loads(response.content))['data']
        # print("Profile", data)
        self.assertEqual(data['username'], self.username)

    def test_dependent(self):
        self.create_profile()
        oath2_token = self.get_access_token()
        self.get_profile(oath2_token)

I did not find any solution to commit the previous API data. If anyone knows please comment. So I have done it this way. I don't know this is the best solution but it works and tested.

Comments

0

Use the --keepdb option when calling manage.py test:

https://docs.djangoproject.com/en/2.1/ref/django-admin/#cmdoption-test-keepdb

It's available since django 1.8. Hope this helps.

Comments

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.