Sooner or later during your development, you will need to deploy your code somewhere. Either cloud or your own servers. One of the best practices for seamless deployment to production is continuous integration. Until you are working alone you won’t need it really. But as your team grows it will help to develop and deploy your product faster.

In software engineering, continuous integration (CI) is the practice of merging all developers’ working copies to shared mainline several times a day. Grady Booch first proposed the term CI in his 1991 method, although he did not advocate integrating several times a day. Extreme programming (XP) adopted the concept of CI and did advocate integrating more than once per day – perhaps as many as tens of times per day.

Django tests on CircleCI

Running Django tests in continuous integration pipeline

One of the important parts of continuous integration is running tests. It is the only way to know that new commits from your teammate didn’t break anything. You probably don’t want to develop something for 2 weeks and then suddenly realize: I broke half of the code. Therefore it makes sense to run tests in your CI pipeline on every git push. Practicing that, you will be notified of every failed test. You should also merge every production change into your feature branch. Tests in the CI pipeline will tell you if your changes + production changes work together.

Set up CircleCI

Firstly, go to CircleCI and sign up with your Github account. After you’ve done that, create a new repository on Github called django_circleci. Clone it and create Django project inside it (you can find the example project here):

django-admin.py startproject django_circleci .

Create a new app:

django-admin.py startapp example

After that, we can add our dummy test. Open example/tests.py and add a dummy test:

# example/tests.py

from django.test import TestCase


# Create your tests here.
class DummyTest(TestCase):

    def test_dummy(self):
        self.assertEqual(True, True)

Now we are able to run our tests locally:

 python manage.py test

You should see output like this:

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Destroying test database for alias 'default'...

As we have done that, we are ready to add a CircleCI configuration. Inside the project, you need to add a directory named .circleci. Inside that folder, you need to create a YAML file called config.yml. Firstly, we need to define a version of the CircleCI configuration. Let’s add this to file which now looks like this:

# .circleci/config.yaml
version: 2.1

After that, we need to define a job that will run our Django tests.

# .circleci/config.yaml
version: 2.1

jobs:
  tests:
    docker:
      - image: circleci/python:3.6.4
    steps:
      - checkout
      - run: sudo chown -R circleci:circleci /usr/local/bin
      - run: sudo chown -R circleci:circleci /usr/local/lib/python3.6/site-packages
      - restore_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
      - run:
          name: Install Dependencies
          command: |
            pip install --user -r requirements.txt
      - save_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
          paths:
            - ".venv"
            - "/usr/local/bin"
            - "/usr/local/lib/python3.6/site-packages"
      - run: python manage.py test

We have to define d which docker image to use for the environment in which we will run our tests:

docker:
      - image: circleci/python:3.6.4

Then we define steps that will execute our tests. Firstly, we check out the code from Github. Then we install requirements/use cached ones. And then the tests are run. Read More Here.

- run: sudo chown -R circleci:circleci /usr/local/bin
      - run: sudo chown -R circleci:circleci /usr/local/lib/python3.6/site-packages
      - restore_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
      - run:
          name: Install Dependencies
          command: |
            pip install --user -r requirements.txt
      - save_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
          paths:
            - ".venv"
            - "/usr/local/bin"
            - "/usr/local/lib/python3.6/site-packages"
      - run: python manage.py test

After that, we need to add a workflow definition to our configuration.

version: 2.1

jobs:
  tests:
    docker:
      - image: circleci/python:3.6.4
    steps:
      - checkout
      - run: sudo chown -R circleci:circleci /usr/local/bin
      - run: sudo chown -R circleci:circleci /usr/local/lib/python3.6/site-packages
      - restore_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
      - run:
          name: Install Dependencies
          command: |
            pip install --user -r requirements.txt
      - save_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
          paths:
            - ".venv"
            - "/usr/local/bin"
            - "/usr/local/lib/python3.6/site-packages"
      - run: python manage.py test

workflows:
  main:
    jobs:
      - tests

When you’ve done that. Add all files to git, commit and push to Github. After that, go to CircleCI and select your Github account. Find your new project on the list and click on its name. Then click the Start building button. After that select Add manually. After that, again click on Start building.

Congratulations, you’ve just run your Django tests on CircleCI.

Using PostgreSQL for Django tests

We’ve succeeded to run our Django tests on CircleCI but SQLite was used as a database. In production environments, you probably won’t use it. Instead, you will use some other SQL databases, for example, PostgreSQL. It makes sense that we use it in tests too. So edit Django settings file to look like this:

# django_circleci/settings.py

... other code ...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'example',
        'USER': 'example',
        'PASSWORD': 'example',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

... other code ...

We need to edit CircleCI config too. We need to add database container. Add this to docker section:

- image: circleci/postgres:9.6.2-alpine
        environment:
          POSTGRES_USER: example
          POSTGRES_PASSWORD: example
          POSTGRES_DB: example

So our config now looks like this:

version: 2.1

jobs:
  tests:
    docker:
      - image: circleci/python:3.6.4
      - image: circleci/postgres:9.6.2-alpine
        environment:
          POSTGRES_USER: example
          POSTGRES_PASSWORD: example
          POSTGRES_DB: example
    steps:
      - checkout
      - run: sudo chown -R circleci:circleci /usr/local/bin
      - run: sudo chown -R circleci:circleci /usr/local/lib/python3.6/site-packages
      - restore_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
      - run:
          name: Install Dependencies
          command: |
            pip install --user -r requirements.txt
      - save_cache:
          key: deps9-{{ .Branch }}-{{ checksum "requirements.txt" }}
          paths:
            - ".venv"
            - "/usr/local/bin"
            - "/usr/local/lib/python3.6/site-packages"
      - run: python manage.py test

workflows:
  main:
    jobs:
      - tests

That’s it. Commit and push again. Check that your tests passed on CircleCI.

Happy coding!

Read more:

Django – Populate database with a custom command


1 Comment

PyCharm tricks every Python developer should know - Jan Giacomelli · March 18, 2020 at 10:23 am

[…] Django tests on CircleCI […]

Leave a Reply