It is surprising how many developers still have no idea how to write tests for their projects. Some of the reasons stopping them, to name a few, are:
Despite all advantages testing can give, they do not test at all.
Let’s assume code is deployed and works fine, it just lacks tests. Write tests when you’ll modify that code, so you’ll check that modifications work. All-at-once approach does not work here.
This may seem funny, but some developers do not run tests for project. They write tests, but never run them :) Thus project has large amount of tests that practically test nothing.
Tests don’t guarantee that you’ll have no errors. Common mistake developers new to testing do may be called ’test everything’. You can’t test everything, unless you want to write tests for your tests. Test important things.
Use test framework that will make you productive: unittest, nose, pytest, etc. There are integration packages for Django and these frameworks, for example, pytest-django and django-nose. Django has built-in support for unittest
.
Whether it’s pytest, unittest, nose or something else, you need to know what it is capable of. For instance, pytest has built-in facilities for monkey patching, temporary dir creation, and test parametrization. On the other hand, nose has profiler plugin.
I noticed that sometimes developers tend to use most powerful tool even if simplest one will do great. For instance, they use Selenium to check simple HTML form, while Django’s built-in django.test.client.Client
, and django-webtest exist.
Mocking is not a panacea. Sometimes it’s better to have small functional test instead of large unit test. It’s good to avoid too much code, especially if it does the same thing: checks that some piece of your project works as expected. Besides, who will check that mock object really looks like object you mock?
I started to use non-django-admin.py approach, and generally I like it. manage.py test appnames
is worse for my project because it requires me to explicitly state what apps it should look for tests in. Separate directory for tests allows me to structure tests any way I want: say, I can store unit tests and functional tests in separate directories in one case, and store them together in other case (for example). So, to conclude, custom Django test runner is not something special, and if you feel you need it, write it—it will save you some time later.
Once I wanted to test form that accepts payment data from payment system in one of projects I support. Easiest way to do that was to test form (it was usual Django form with bunch of fields and validation). But I quickly realized that later I’ll want to test view related to that form, and tests will definitely look same. That’s why I decided to write functional tests for view instead of tests for both form and view. That saved me time and money, because I found few bugs and checked that view and form nicely operate and interoperate.
This blog is about things I encounter while doing web and non-web software development.