Coverage, so that it reports only the packages and directories of interest.
And also, you'll learn how to install and use Factory ...'>
Mar 20 2014

Tools for Testing in Django: Nose, Coverage and Factory Boy

published by Marina Mele
in blog Python, Science and Marketing
original entryTools for Testing in Django: Nose, Coverage and Factory Boy

django testing


In this post, you will learn how to install and use Nose, a tool for running your tests in Django.
You'll learn how to run and configure Coverage, so that it reports only the packages and directories of interest.
And also, you'll learn how to install and use Factory Boy in your tests (an alternative to Fixtures).

If you want to learn more about testing, check this post about Django testing: Doctests and Unittests.

First of all, why test with Nose?


These are some of the reasons why you should try Nose for testing:
  • Extends the functionalities of unittest
  • It tests your apps by default, and not all the standard ones that are included in the INSTALLED_APPS of your settings file
  • It detects all the functions and classes that start with Test or test that you have defined in your code, so no more worrying about how can I make my tests visible to the Test Suite?
  • You can test specific apps, folders, files or tests
  • You can use all the nose plugins
  • And much more!! Comment if you think I forgot something important! ;-)

Let's start with Django Nose!


First, activate your testing environment and install nose and django-nose via pip:

$ pip install nose
$ pip install django-nose

don't forget to add them in your requirements file for the testing environment. Then, add django-nose to the installed apps in your testing settings.py file:

INSTALLED_APPS = (
    ...
    'django_nose',
    ...
)

Note: if you use South, make sure you include it before django_nose in the installed apps. This is because South installs its own test command that turns off migrations during testing. This way, you make sure that the django_nose's test command is used.

In case you have a testing settings file that inherits from another settings file that contains all your installed apps, you can add this package by:

from .settings import *
INSTALLED_APPS += ('django_nose',)

Finaly, you have to indicate Django to use the Nose test runner. In the test settings file add:

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

Save and make sure everything is installed properly by running

$ python manage.py test


If you get an error like "permission denied to create database" check this post on Django testing.


Coverage Library


This library is an amazing tool that tells you which parts of your code are covered by tests. It is nicely integrated with django-nose, so to install it, just run:

$ pip install coverage

Then, you can run coverage with

$ python manage.py test --with-coverage

If you want to run your tests with this default behavior, open your test settings file and add the following:

NOSE_ARGS = [
    '--with-coverage',
    '--cover-package=myapp1, myapp2',
    '--cover-inclusive',


The second option, --cover-package indicates the packages to cover with coverage. In this case we cover two apps, myapp1 and myapp2 (these names are the ones you use in INSTALLED_APPS). And the third option, --cover-inclusive, indicates coverage to scan all the files in the working directories (this is useful to find files that are not being test).

After this configuration, when you run

$ python manage.py test

only the packages myapp1 and myapp2 will be tested, and you'll see the corresponding coverage report. However, if you are using South, this report includes all your migration files, and your overall cover score will be affected.

In order to omit these files, create a file in the root directory (at the same level of manage.py) named .coveragerc and write the following:

[run]
omit = ../*migrations*

Run your tests again and you'll see that the migrations don't show in the coverage report :-)

If you change the verbosity displayed in your tests, by adding -v 3

$ python manage.py test -v 3

you'll see that every time you run the tests, a new database is created and then all the South fixtures are applied. This can take some time, so if you want to prevent this from happening, there are two different ways:

  • Create and reuse a database for testing. With this method, you can create a database for testing, and instead of deleting it when all the tests are done, it remains there to be reused every time the tests are run. You can find more information in this post.
  • Disable South migrations in your tests. With this method, when the database is created, instead of running manage.py migrate in the apps managed by South, it runs directly manage.py syncdb. To use this method, open the settings.py file you use for testing and add:
          SOUTH_TESTS_MIGRATE = False

Now your tests will run faster!


Factory Boy


As recommended by the 2 Scoops of Django book (amazing Best practices book!) fixtures are hard to maintain as the project evolves and data structures change. One alternative they recommend is the library factory_boy, which helps in the creation of models in your tests.

To install it, use pip:

$ pip install factory_boy

And that's it! :-)

Now, let's look an example of a test that uses some Nose tools and a Factory Model! First, we create a model in models.py:

Next, we create the tests for that model:

Note that:

  • We create a model with 3 different mandatory fields: location, rooms and balkon.
  • In the test file, we create the class HouseFactory, which creates instances of a House every time is called. 
  • By default, HouseFactory creates a house in Barcelona with 3 rooms. But as balkon does not have any default value, we need to specify it when we create the new instance.
  • We can override any default value by specifying it when a new instance is created. 
  • Nose provides extra tools for testing. Here we show the function eq_, which may not be very interesting, as it is equivalent to assertEqual... :-) Check out other functions in nose.tools here
  • And check out the extra tools for testing that provides django-nose here
Now it's time you create your tests! 
+1 if this was helpful! ;-)

Want more? Check out the index page to see what else you can learn here! :-)

Tag cloud


Social Sharing

Feeds