Goの単体テストとGitHubActionsでビルド・テストしてみる
概要
こちらの続き。
単体テストとGitHubActionsでビルド・テストを実行してみる。
環境
M1 Mac
docker desktop 4.17.0
まずはローカルでの構築
事前準備
今回はDB接続(infrastructure)モジュールのテストをするので、コンテナ上のMysqlにデータ登録する。
なので、コンテナ起動時にDDL実行するように↓のsqlファイルを用意しておく。
init.sql
SET
GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';
SET
session sql_mode = 'NO_ENGINE_SUBSTITUTION';
DROP TABLE IF EXISTS users;
CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
INSERT INTO testdb.users
(id, user_name, created_at, updated_at, deleted_at)
VALUES(1, 'test', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL);
docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
target: dev
dockerfile: Dockerfile
env_file: .env
tty: true
container_name: gin-api
depends_on:
- db
volumes:
- ./:/go/src/app
ports:
- 8080:${SERVER_PORT}
- 2345:2345
db:
image: mysql:8.0
platform: linux/arm64
tty: true
container_name: ${MYSQL_HOST}
env_file: .env
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: ${MYSQL_TZ}
ports:
- 3306:${MYSQL_PORT}
volumes:
- data-mysql:/var/lib/mysql
- ./db/mysql/log:/var/log/mysql
- ./db/mysql/etc/my.cnf:/etc/mysql/conf.d/my.cnf
- ./db/mysql/init:/docker-entrypoint-initdb.d → ここでsqlファイルの場所を記述
volumes:
data-mysql:
テストモジュール
user_repository_test.go
ファイル名は末尾に_testをつけるらしい。
テストの関数名はググったもの参考に。(参考になる記事はたくさんありました)
とりあえず、動かしたいので、2ケースだけ作成。
・ケース1
userテーブルのID=1のデータがあるかチェック
・ケース2
userテーブルのID=2のデータがないかチェック(なければOK)
package mysql
import (
"go-gin-api/config"
"testing"
)
func TestMain(m *testing.M) {
m.Run()
}
func Test(t *testing.T) {
Connect(config.Config.MysqlHost, config.Config.MysqlUser, config.Config.MysqlPass, config.Config.MysqlPort, config.Config.MysqlDbName)
db, _ := DB.DB()
defer db.Close()
ur := NewUserRepository(db)
data1, err := ur.FindByID(1)
if err != nil {
t.Errorf("Calc() error = %v, wantErr %v", err, "")
return
}
if data1.ID != 1 {
t.Errorf("func FindByID = %v, want %v", data1.ID, "1")
}
data2, err := ur.FindByID(2)
if err != nil {
t.Errorf("Calc() error = %v, wantErr %v", err, "")
return
}
if data2.ID != 0 {
t.Errorf("func FindByID = %v, want %v", data2.ID, "0")
}
}
動作確認
まずはコンテナ起動
(コンテナ上でMysqlもGoも動かす)
docker-compose up -d
テスト実行
-vオプションつけるとログを詳細に出してくれるらしい。
実行対象に./...を指定すると配下のディレクトリのテストをすべて実行してくれるらしい。
docker container exec -it gin-api go test -v ./...
テスト通った。
GitHubActions
ローカルでは動かせるようになったので、今度はGitHubActionsで動かせるようにしていく。
大まかには↓の流れになるように構築する。
- Mysqlのコンテナ起動
- ソースコードをチェックアウト
- DDL実行(テストデータ投入)
- ビルド
- テスト実行
準備
GitHubActionsは↓のようにworkflowsディレクトリ配下にymlファイルを配置しておくことで、任意のイベント(pushなど)発生時に自動的に記述したワークフローを実行してくれる。
.github/workflows/*.yml
なので、ディレクトリとymlファイルを作成。
今回は
.github/workflows/goci.yml
とする。
ymlの記述
今回記述したymlはこんなかんじ。
ほとんどはGitHubの公式ドキュメントの記述を参考にした。
何度か動かしつつ、トライ&エラー(環境変数の設定や読み込みでつまづいた)を繰り返した。
ユーザ名やパスワードなどはベタ書きしてしまっているが、シークレットに設定しておいてそこから読みこむことも可能。(今回はそこまではやらない)
name: Go Build and Test
on:
push:
branches:
- 'main'
- 'releases/**'
- 'develop'
pull_request:
types:
- closed
branches:
- 'main'
- 'releases/**'
- 'develop'
jobs:
build-and-test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
ports:
- 3306:"3306"
env:
MYSQL_ROOT_PASSWORD: testpassword1
MYSQL_DATABASE: testdb
MYSQL_USER: testuser
MYSQL_PASSWORD: testpassword2
MYSQL_TZ: Asia/Tokyo
options: --health-cmd "mysqladmin ping -h 127.0.0.1" --health-interval 20s --health-timeout 10s --health-retries 10
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "1.20"
- name: Copy DDL file
run: cp db/mysql/init/init.sql ${{ github.workspace }}
- name: Execute DDL
run: |
mysql -h 127.0.0.1 --port 3306 -uroot -ptestpassword1 -D testdb < db/mysql/init/init.sql
- name: Install dependencies
run: go get . && go mod tidy
- name: Build the code
run: go build -v ./...
- name: Run tests
run: go test -v ./...
env:
SERVER_PORT: 8080
MYSQL_HOST: localhost
MYSQL_DATABASE: testdb
MYSQL_USER: testuser
MYSQL_PASSWORD: testpassword2
MYSQL_PORT: 3306
MYSQL_TZ: Asia/Tokyo
動作確認
mainにpushすると自動的に定義したワークフローが実行される。
少し待つと終わった。
テスト通ったみたい。
感想
とりあえず動くものを、、、ということでお試しで実装してみたが、Goは標準ライブラリが充実していて使いやすい。
GithubActionsもクセもなく、けっこう直感的にやりたいこと書けた。
リファクタリングはまた今度やろうと思う。(やぶん、やらない)
Discussion