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).
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:
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")
- 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 filetest_<name>.py
. - Use the correct
assert*
method depending of your case.
List of assert*
methods
The most commonly used:
Method | Checks 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