TEST DJANGO APPS QUICKLY
I'm sure you agree that you have to check to see that your codes do what you expect them to do.
Manually testing your code may come as default...
- You go through the user interface and imitate the processes users are expected to follow.
- You use some "print" statements to check inputs and outputs.
- Where a process depends on some database items, you create dummy objects.
- After all these, you ship your application...phew!
...you think you finally finished the project!
Well most of the time, you thought wrong! It is either a bug snuck through or a new feature needs to be added! - You work on whatever it is and ship the application again.
- Suddenly, you are called on that the interface you tested and tested and wrote many print statements for failed to work!
You see where I'm headed with this;
-You do your manual testing all over again and the cycle continues, non-stop!
AUTOMATE TESTING
Apart from being a good developer by writing tests, you save yourself tons of workload albeit in the future.
- You write the test
- You run the test
- You ship the application.
Modifications? - You modify
- You run the test
- You ship the application.
New feature? - You add feature
- You run the test
- You ship the application.
You write the test for your module once and you get to run it as often as you like.
ENOUGH WITH THE TESTING ADVOCACY!
Django documentation expains writing tests
Creating dummy data in your test functions could feel scary and overwhelming especially when you need to populate your database. One way to test quickly is using https://model-bakery.readthedocs.io/en/latest/index.html. It creates the fixtures you need to test your application while you concentrate on writing your tests.
HOW TO USE MODEL BAKERY
Let us assume we have a books app
In our models.py:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=250)
joined = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
def book_list(self):
return self.book_set.all()
def active_book_list(self):
return self.book_set.filter(published=True)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=250)
synopsis = models.TextField()
published = models.BooleanField()
pages = models.IntegerField()
def __str__(self):
return f"{self.title} by {self.author.name}"
To use bakery, run: pip install model_bakery
In your tests.py file,
from django.test import TestCase
from model_bakery import baker
from books.models import Author, Book
class AuthorTest(TestCase):
def setUp(self):
#create a dummy author
self.author = baker.make(Author)
#create published books by the author
self.published_books = baker.make(Book, author=self.author, _quantity=5)
#the first argument is the model of the object you want to create
#the second argument, which is optional, is the field(s) you want to #provide value for. It is necessary here because I want to test the #books written by self.author. If I do not set it, bakery will #autogenerate random author(s) for the book(s)
#the third argument, which is also optional, is the quantity of objects to #be created
self.unpublished_books = baker.make(Book, author=self.author, _quantity=5)
#to test that our active_book_list function works properly
def test_active_book_list(self):
author = self.author
published_books = self.author.active_book_list()
number_of_published_books = len(published_books)
self.assertEqual(number_of_pulished_books, 5)
#self.author has 10 books in total but we expect this function to give #return 5 books
Now run: python manage.py test
to test your project
Or run : python manage.py test books
to test only your books app
Your terminal output should look something like:
So, everytime you fix a bug or add new features run: python manage.py test
to test your project or run : python manage.py test books
to test only your books app to test that your active_book_list module works as it should.
Feel free to suggest improvements to the post!
I followed the steps and it worked really good for me.
Thanks for the feedback!
I see the console states 9 tests were run, what were they? As there’s just 1 test.py file and only 1 test inside of it. test_active_book_list… please clarify
That is sample output from running a successful test. In that test.py file, there were 9 tests
ok, we agree on amount, what were they testing specifically? as I see only 1 assert. usually I see a test- then a expected output, and if that fails an assert.
We created 5 published books and 5 unpublished books. We are testing the active_book_list function which returns only published books, hence,
self.assertEqual(number_of_pulished_books, 5)