Skip to main content

Integration Tests

Integration tests allows us to test the features of the code.

This is an important thing to do, to avoid regressions (if we add a new feature, we want to be sure we're not breaking another feature).

Why Integration tests?

There are different types of tests:

  • Unit tests are tests that test a single function or a single class.
  • Integration tests are tests that test the interaction between different parts of the code.
  • End-to-end tests are tests that test the whole application, from the front end to the back end.

On Nantral Platform, we choose to focus on integration tests, because they are easy to implement and allow us to quickly find potential bugs or security issues.

Philosophy

A good integration test is a test that reproduces the user experience. It should, for a given API route:

  • test the result (correctness)
  • test the permissions (security)
  • test the error handling (robustness)

Write a test

To add a test for a route, create a tests.py file in the app you want to test.

Here is an example of a test file, which test the example of the Create an API app pages:

apps/event/tests.py
from rest_framework import status, test

from .models import Event

class RetrieveEventTestCase(test.APITestCase):
# Set up database objects for the whole TestCase
@classmethod
def setUpTestData(cls):
cls.event = Event.objects.create(
name="My event",
start_date="2022-01-01",
end_date="2022-01-02",
)
cls.user = User.objects.create_user(email="test@example.com")
cls.admin = User.objects.create_super_user(email="admin@example.com")

# the test method must begin with "test_"
def test_get_event_not_authenticated(self):
response = self.client.get(f"/api/event/{self.event.id}/")
# check response is forbidden
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

# another test method
def test_get_event_authenticated(self):
# use force_authenticate to bypass validation (email, temporary accounts)
self.client.force_authenticate(self.user)
response = self.client.get(f"/api/event/{self.event.id}/")
# check response if authorized
self.assertEqual(response.status_code, status.HTTP_200_OK)
# check the content is OK and name has not been modified
self.assertEqual(response.data["name"], "My event")
Good practices
  • You should write 1 class per route
  • If you have too many tests in an app, you can split your tests in multiple files placed in a tests folder and rename each file test_<name>.py.
  • Use the correct assert* method depending of your case.
List of assert* methods

The most commonly used:

MethodChecks that
assertEqual(a, b)
assertNotEqual(a, b)
a == b
a != b
assertTrue(x)
assertFalse(x)
bool(x) is True
bool(x) is False
assertIsNone(x)
assertIsNotNone(x)
x is None
x is not None
assertIn(a, b)
assertNotIn(a, b)
a in b
a not in b
assertAlmostEqual(a, b)
assertNotAlmostEqual(a, b)
round(a-b, 7) == 0
round(a-b, 7) != 0
assertGreater(a, b)
assertLess(a, b)
a > b
a < b
assertGreaterEqual(a, b)
assertLessEqual(a, b)
a >= b
a <= b
assertRegex(s, r)
assertNotRegex(s, r)
r.search(s)
not r.search(s)
assertCountEqual(a, b)a and b have the same elements in the same number, regardless of their order.

Check out the list of assert* methods in Python and the list of assert* methods specific to Django.

Run the tests

You can run the tests of a specific app with this command:

pipenv run test apps.event

You can also run the tests for all apps at once:

pipenv run test