Wiremock on Github with Github Actions

Story on how to use Wiremock to run CI on Github with Github Actions

This story setup a basic Django project using Docker and Docker Compose and then use Wiremock to run tests against a stubbed external API, both locally and on Github via Github Actions.

Prerequisites

I won't be showing everything in detail here but rather focus on what is relevant for this story, eg. docker-compose and github actions.

This will not be a complete from zero to hero tutorial, rather I'll assume that you know enough basic Django and Docker to be able to apply the shown yourself.

requirements.txt

asgiref==3.5.0
attrs==21.4.0
backports.zoneinfo==0.2.1
certifi==2021.10.8
charset-normalizer==2.0.12
Django==4.0.4
gunicorn==20.1.0
idna==3.3
iniconfig==1.1.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.0.8
pytest==7.1.1
pytest-django==4.5.2
requests==2.27.1
sqlparse==0.4.2
tomli==2.0.1
urllib3==1.26.9

docker-compose.yml

version: '3.7'

services:
  django:
    restart: always
    build: 
      dockerfile: ./docker/Dockerfile
      context: .
    environment:
      - DEBUG=1
      - PYTHONDONTWRITEBYTECODE=1
      - PYTHONUNBUFFERED=1
      - ENV=DOCKER_LOCAL
      - PORT=8000
    ports:
      - 8000:8000
    volumes:
      - .:/app
    command: /usr/local/bin/gunicorn config.wsgi:application -w 2 -b :8000 --reload

  wiremock:
    image: wiremock/wiremock
    ports:
      - "8080:8080"
      - "8443:8443"
    volumes:
      - ./wiremock:/home/wiremock

Dockerfile

FROM python:3.8

ARG APP_USER=appuser
RUN groupadd -r ${APP_USER} && useradd --no-log-init -r -g ${APP_USER} ${APP_USER}

EXPOSE 8000
WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DEBUG 0

RUN apt-get update && apt-get install
RUN apt-get install -y \
  libpq-dev \
  libmariadb-dev-compat \
  libmariadb-dev \
  gcc git \
  && apt-get clean

RUN pip install -U pip

COPY ./requirements.txt /app/requirements.txt
RUN python -m pip install -r /app/requirements.txt
COPY . /app/

RUN mkdir -p /app/media
RUN mkdir -p /app/staticfiles

RUN chown -R ${APP_USER}:${APP_USER} /app/media
RUN chown -R ${APP_USER}:${APP_USER} /app/staticfiles

.github/workflows/push.yml

name: Python application

on:
  push:
    branches: [ master ]

jobs:
  build_and_test:
    runs-on: ubuntu-latest
    services:
      wiremock:
        image: wiremock/wiremock
        ports:
          - 8080:8080

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.8
      uses: actions/setup-python@v3
      with:
        python-version: 3.8
    - name: curl
      run: sudo apt-get install -y curl
    - name: import stubs to wiremock
      run: curl -v -d @./wiremock/mappings/externalapi-stubs.json http://localhost:8080/__admin/mappings/import
    - name: install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Run migrations
      run: python manage.py migrate
      env:
        ENV: GITHUB_ACTION_CI
    - name: Run tests with pytest
      run: pytest
      env:
        ENV: GITHUB_ACTION_CI

pytest.ini

[pytest]
DJANGO_SETTINGS_MODULE = config.settings
# -- recommended but optional:
python_files = tests.py test_*.py *_tests.py

company/tests.py

from django.test import TestCase
import requests


def test_get_the_api_response():
    url = "http://localhost:8080/helloworld"
    r = requests.get(url)

    assert r.status_code == 200
    assert r.text == "hello world"

wiremock/mappings/externalapi-stubs.json

{
  "mappings" : [  {
    "id" : "f5d37aa8-e436-491a-8e80-570f55b34d14",
    "name" : "hello world",
    "request" : {
      "url" : "/helloworld",
      "method" : "GET"
    },
    "response" : {
      "status" : 200,
      "body" : "hello world",
      "headers" : { }
    },
    "uuid" : "f5d37aa8-e436-491a-8e80-570f55b34d14",
    "persistent" : true,
    "priority" : 5
  } ],
  "meta" : {
    "total" : 1
  }
}

References

wiremock