💽
Github ActionsでMySQLに接続してDjango REST Frameworkのunittestを実行したい
背景
Django REST FrameworkでAPIサーバーを作成したが、CI環境を作ったことが無かったのでGithub Actionsでunittestを実行させてみた。
その際にデータベースとの接続でかなりつまずいたので、まとめておきます。
(他にも沢山苦労しましたが、Github Actionsが関連するポイントとして上記をまとめようと思いました)
本題
では具体的に引っかかった点と解決方法を説明します。
Github Actions上におけるDatabaseとの接続方法
今回のケースでは、以下のようなdocker-compose.yml
を用意し、DjangoアプリケーションとMySQLを接続していました。
version: "3"
services:
web:
container_name: django-container
image: python:3.9.1
working_dir: /code
ports:
- 8000:8000
volumes:
- .:/code
tty: true
depends_on:
- db
db:
container_name: mysql-container
image: mysql:8.0
environment:
MYSQL_DATABASE: test-db
MYSQL_ROOT_USER: test-user
MYSQL_ROOT_PASSWORD: example
ports:
- 3306:3306
また、テストコードは以下のようにviewの振る舞いを確認する内容なっており、MySQLに格納されるデータを参照するようになっています。
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework_simplejwt.tokens import RefreshToken
from api.tests.factory import UserFactory, DrinkFactory
class DrinkModelViewSetTestCase(APITestCase):
# Drinkを正常に作成(POST)できることを確認
def test_status_code_when_post_drink(self):
# 認証に必要なtokenをheaderにセットする
user = UserFactory()
token = str(RefreshToken.for_user(user).access_token)
self.client.credentials(HTTP_AUTHORIZATION='JWT ' + token)
# テスト対象のURLを取得
url = reverse('drink-list')
# POSTするデータ
data = {
'drink_name': 'Water',
'price': 100,
}
response = self.client.post(url, data, format='json')
# POSTした結果のstatus_codeが201であることを確認
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
また、Github Actionsでデフォルトで用意されているDjangoのworkflowであるdjango.yml
は以下の内容になっています。
name: Django CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
run: |
python manage.py test
このworkflowをそのまま設定すると、Githubの仮想環境上ではMySQLが起動しておらず、接続ができないため失敗します。
そのためGithub上でMySQLを起動してあげる必要があります。
解決策
django.yml
のInstall Dependencies
の直前に以下のstepを追加しました。
# Github上にdockerコンテナを起動させる
- name: Docker Container Create
run: |
docker-compose up -d
docker-compose up -d
sleep 20s
# コンテナが起動しているかログに出力する
docker-compose ps
# MySQLが8.0なのでユーザーの認証方法を変更する
- name: Set up Mysql
run: |
docker exec -t mysql-container mysql -u test-user -pexample -e"ALTER USER 'test-user'@'%' IDENTIFIED WITH mysql_native_password BY 'example';"
Github上でMySQLのコンテナを立ち上げることで、接続可能なデータベースを用意することができます。
また、pythonのコマンドもコンテナ内で実行するように修正します。
- name: Install Dependencies
run: |
docker exec -t django-container python -m pip install --upgrade pip
docker exec -t django-container pip install -r requirements.txt
- name: Run Tests
run: |
docker exec -t django-container python manage.py test
これでGithub上でもMySQLに接続し、ユニットテストが通るようになるはずです!
まとめ
- Github上にMySQLのDockerコンテナを作成して上げるとデータベースとも接続できる
※もっと効率的な方法をご存知の方がいらっしゃったらご指摘いただけますと幸いです
Discussion