Testing in Python: using Django

2 Comments

As promised! Let’s dig in to how we run tests using Django.

We run a web server using apache where the code is written using Django. We put information regarding the state of the optmization worker jobs, advertiser/publisher data upload systems and such for other engineers and analysts to use.

How to run Django test suites per application:
We run Django tests separately on our testing framework. We run Django tests with the command:

1
$ python path/to/manage.py test

Django tests are documented at https://docs.djangoproject.com/en/dev/topics/testing/. The document tells you that if you have a Django application, we can put our tests in the application directory’s file named tests.py. Let’s name the application app1.

What they say:

1
2
3
4
$ ls www
app1
$ ls app1/
tests.py

However, I don’t like this test organization. If we write many tests, the tests.py file will be huge. Also I want the filename to reflect which module is being tested.

What I want:

1
2
3
4
5
6
7
8
$ ls www
app1
$ ls app1/
some_files tests
$ ls app1/tests/
views/ models/
$ ls app1/tests/views
test_main_page.py

You want to keep not only the tests but also the test organization as clean as possible.

How do we achieve this? It is actually a tough job to do, and I had to search quite a bit, but now it works!

1. Write your application. Have the application in the www directory (or Django root directory).

2. Create tests and place them in appropriate location where you think they belong. As in our example, we put them in app1/tests/views/test_main_page.py, app1/tests/models/test_model.py etc. Make sure that you have the Django unit test import statement in your test files as covered in the Django docs.

1
import django.utils.unittest

3. Add the application in the tuple INSTALLED_APPS in settings.py

4. In apache.django.wsgi add the Django main directory to the system path

1
sys.path.append('/path/to/www/')

5. Add __init__.py to app1/tests/, app1/tests/views/, app1/tests/models/, etc. to all the subdirectories so the tests can be referred as modules

6. Import the test classes from the test module you wrote in the app1/__init__.py by putting the following line:

1
2
from www.app1.tests.views.test_main_page import
TestModuleFunctions, TestMainPage

7. app1/tests/views/__init__.py can be empty

8. To make the test easier by using in-memory db for testing functions, you must add the following code to settings.py for every db key used in the tests.

1
2
3
4
5
if 'test' in sys.argv:
DATABASES[db_key] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': test_db_name
}

Ok that is it! Now it should work by typing the command:

1
python path/to/www/manage.py test app1

You can add the command to the Jenkins configuration.

I hope you enjoyed our blog entry and found it useful. Writing tests makes your code better. It is much easier to stub-out/mock aggregated objects than module objects. You take more care in designing your modules/classes/functions.

This entry was posted in Developer Tools, Optimization, Python, Uncategorized. Bookmark the permalink.

2 Comments
  • sagiv

    Did you write anything new using your API?
    Appnexus App Or plugin for Django?

    • Yuki

      Hi sagiv, I am not on the api team but I have used the Appnexus API… however, they are all internal processes. My team, optimization team, has not written API’s for outside use, although we may do so in the future.