CI | tutorial Tue 28 February 2012 Olivier Mansion

With ShiningPanda CI it has never been so easy to run tests against databases. Starting a database server on the fly is literally one click away from your job configuration!

Let’s see how with this tutorial in two parts that describes how to test your existing projects on multiple databases:

  • The first part deals with writing and running tests against databases,
  • The second part deals with integration with Jenkins.

Sample project

This tutorial is based on the poll application from the Django tutorial.

It describes all the required steps to run your Django tests on multiple databases.

The source code can be found here. This sample project is organized as follow:

The following features are implemented:

  • Poll management via the Django admin site,
  • Vote submission.

Don't forget to install Django!

1 $ pip install Django

Testing tools

In this tutorial, the following tools are used:

  • django-jenkins: a Django test runner dedicated to Jenkins,
  • coverage: a tool for measuring code coverage of Python programs,
  • pylint: analyzes Python source code looking for bugs and signs of poor quality.

Install them all by typing:

1 $ pip install django-jenkins coverage pylint

Write test

A good start is to have a look at Django documentation.

Then let's have a look on the models located in djangotutorial/polls/models.py:

1 class Poll(models.Model):
2     question = models.CharField(max_length=200)
3     pub_date = models.DateTimeField('date published')
4 
5     def was_published_today(self):
6         return self.pub_date.date() == datetime.date.today()

Our goal in this tutorial is to test Poll.was_published_today on multiple databases.

First create a tests module in djangotutorial.polls (a file djangotutorial/polls/tests.py).

To write a test, just create a class that inherits from django.test.TestCase and add as many test methods you want.

 1 import datetime
 2 from django.test import TestCase
 3 from polls.models import Poll
 4 
 5 class ModelsTest(TestCase):
 6 
 7     def test_poll_was_published_today(self):
 8         poll = Poll.objects.create(
 9             question='ShiningPanda is awesome no?',
10             pub_date=datetime.datetime.now(),
11         )
12         self.assertTrue(poll.was_published_today())

Here we are adding a test_poll_was_published_today methods that creates a new Poll object with its publication date set to current date and time (pub_date=datetime.datetime.now()) and then asserts that Poll.was_published_today returns True.

Now it's time to run this test!

Run tests

To run the test, just execute:

1 $ python djangotutorial/manage.py test polls
2 Creating test database for alias 'default'...
3 .
4 ----------------------------------------------------------------------
5 Ran 1 test in 0.001s
6 
7 OK
8 Destroying test database for alias 'default'...

Note that polls is the name of the application to test.

What about Jenkins?

Now we want this project to be ready for Jenkins.

Edit djangotutorial/settings.py and add the following if block at the end of it (don't forget to import os):

 1 DATABASES = {
 2     'default': {
 3         'ENGINE': 'django.db.backends.sqlite3',
 4         'NAME': 'djangotutorial',
 5         # Other parameters
 6     }
 7 }
 8 # [...]
 9 if os.getenv('JENKINS_URL', False):
10     INSTALLED_APPS += ('django_jenkins', )
11     PROJECT_APPS = ('polls', )
12     DATABASES['default'].update(dict(
13         ENGINE=os.getenv('DBA_SQL_DJANGO_ENGINE'),
14         USER=os.getenv('DBA_SQL_ADMIN'),
15         PASSWORD=os.getenv('DBA_SQL_ADMIN_PASSWORD'),
16         HOST=os.getenv('DBA_SQL_HOST'),
17         PORT=os.getenv('DBA_SQL_PORT'),
18     ))

Let's have a look on this block:

  • if os.getenv('JENKINS_URL', False): activate this configuration only on Jenkins,
  • INSTALLED_APPS += ('django_jenkins', ): enable django_jenkins features,
  • PROJECT_APPS = ('polls', ): list applications to test,
  • DATABASES['default'].update(...): update database connection parameters from environment variables exported by Jenkins.

Now let's run tests by mocking Jenkins environment:

1 $ JENKINS_URL=1 DBA_SQL_DJANGO_ENGINE=django.db.backends.sqlite3 python djangotutorial/manage.py jenkins
2 Creating test database for alias 'default'...
3 .----------------------------------------------------------------------
4 Ran 1 test in 0.003s
5 
6 OK
7 Destroying test database for alias 'default'...

Check that the reports folder created:

1 $ ls reports
2 TEST-polls.tests.ModelsTest.xml coverage.xml pylint.report

It contains some useful data for Jenkins:

  • TEST-polls.tests.ModelsTest.xml: test results,
  • coverage.xml: code coverage analysis,
  • pylint.report: static code analysis.

This project is now Jenkins ready!

What's next?

Check our next blog post out to have a look on how to integrate this project with Jenkins!


Made with love: Tomotcha