Unit Testing in Django

Testing is a essential step for software development process. Many developers ignore this step and ended up finding bugs in production.

Manual testing is fine until your application grows on a large scale. Once your application is big  you cant test each and every component of your application whenever you make a change or introduce new features. That’s where unit testing comes in picture.

Unit testing is an automated way of testing your application. You write tests for all the units/components you want to test and it will do its job.

How does Unit Testing in Django work?

When we create our django app using python manage.py createapp app_name it creates a tests.py in our app directory. This file is used by django to run all unit tests for models and other components within the app. In test file we inherit django’s test class TestCase or DRF’s test class APITestCase and write our own test functions. These function names start with name ‘test_’ . setUp(self) and tearDown(self) are used to setup required environment and clean up after running test. Django uses a separate database from whatever database we access in out development and destroys it after running all tests.

Lets create unit test for APIs

Prerequisites

Virtual Environment setup for a Django project.

Django rest framework setup

Basic API endpoints created

Files Structure in Django:-

Django gives tests.py file in app, but if our app big in size and components then we have to write tests in multiple files to keep everything clean and sorted. For that we have to create directory with name tests in app directory and create all test file start with name “test_”.

Now lets see a basic unit test  for login api…

 

Here we are testing login api functionality. Unit test start testing a function in isolation thats why we have create required attributes to run a login api. Here user needs to be there in order to login so we have created a user in our setUp function. If every information is given correct like credentials, authentication token, api url then test will run successfully. A self.assertSomething() verifies values passes through arguments are correctly matching. These values are nothing but out expected outputs from api response. We can call multiple assert functions, if all functions returns true as boolean then test is identified as successful otherwise failed.

We have multiple type of Assert Functions:-

 

Test Database for unit tests

When we run our tests by default Django create a database and destroys it after finalization. This is to avoid conflicts between our production and/or development database. We can define and customize a separate database for tests specifically in DATABASE dictionary in settings.py file something like:

 

Running Your Tests

python manage.py test will search all your tests files and execute them and will show success and error for each testcase.

We can  customize this command to run some specific test cases and avoid running all the test cases

  • python manage.py test app_name runs tests only of specific app
  • python manage.py test app_name.test_file_name runs tests only for given file
  • python manage.py test app_name.test_file_name.ClassName runs tests only for given class
  • python manage.py test app_name.test_file_name.ClassName.test_function runs only given test function

Making Unit test Faster

As long as we are testing our mid size application with limited test cases running tests in basic way works fine (using command python manage.py test) and speed of testing doesn’t bother us. But as our application grows on large scale running all the test in one go becomes slow. That is because major time takes in creating database running all our migrations and running all our testcases one by one. We can reduce significant amount of time by using –keepdb  and –parallel. As unit test doesn’t depends on each other so we can run them in  parallel. Keepdb will avoid erasing database between each test. We can use these feature easily by using:

python manage.py test -keepdb –parallel 

Its not mandatory to use them together.

This is it for this blog, if you have any doubts we can discuss them in comment section.

Recommended links

https://docs.djangoproject.com/en/3.2/topics/testing/overview/

https://www.django-rest-framework.org/api-guide/testing/

 

Comments