はじめに
CIでE2Eテストを回すときに、問題となるのは実行時間です。
弊社で用意しているE2Eテストはすべてのテストケースを実行するのに40〜50分かかります。
これを毎Push、毎Pull Requestごとに実行するのはちょっとつらいです。
開発ブランチにおいては、修正した箇所のみE2Eテストを実行できたら嬉しいですよね。
LIFULLのSETGで使っているテストツールBuckyには実行対象となるテストケースをラベルで絞り込む機能があります。
今回はそのBukcyのラベル機能とGitHubのPull Requestのラベルを組み合わせることで、テストしたい部分にだけCI上でE2Eテストをかけられる仕組みを考えました。
テストを実行する範囲のイメージとしてはこんな感じです。
※リグレッションテストの効果が薄まるので、統合環境ではすべてのテストを実行するようにしましょう。
テスト対象
テスト対象はBuckyのテスト結果表示アプリケーションであるBucky-Managementを使います。
Bucky-Managementは以下の5つのページが存在します。
- トップ
- テスト結果一覧
- テスト結果詳細
- テストスイート一覧
- テストスイート詳細
テスト作成
それではBuckyでテストを作成していきます。
このようにyamlでテストケースを作成することができます。
Buckyの使い方に関してはこちらをご覧ください。
https://qiita.com/rueyjye/items/570ce17d698819f99091
desc: トップ画面に関係するテスト
device: pc
service: bucky_management
priority: high
test_category: e2e
labels: TOP #ラベルを指定
cases:
- case_name: top_1
func: 右上のグラフのタイトル表示
desc: 右上のグラフのタイトル表示の検証
procs:
- proc: open page
exec:
operate: go
url: <%= ENV['BUCKY_FQDN'] %>/
- proc: 右上のグラフのタイトルが「Latest Result e2e-pc」であること
exec:
verify: assert_text
page: top
part: title_e2e_pc
expect: Latest Result e2e-pc
注目していただきたいのはlabels: TOP
の部分です。
ラベルを記入しておくことで、テスト実行時にオプションを指定すればこのテストケースのみ実行できるようになります。
上記のテストケースと同様に他のページでもテストケースを作成しておきます。
それぞれのテストケースにラベルも記入してあります。
.
├── result_detail.yml # テスト結果詳細
├── result_list.yml # テスト結果一覧
├── suite_detail.yml # テストスイート詳細
├── suite_list.yml # テストスイート一覧
└── top.yml # トップ
GitHub Actions
CIはGitHub Actionsを使います。
作成したWorkflowは以下です。
name: System testing
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Cache docker image of Bucky-Management
uses: actions/cache@v1
with:
path: ~/caches
key: ${{ runner.os }}-build-${{ hashFiles('Dockerfile') }}
restore-keys: |
${{ runner.os }}-build-${{ hashFiles('Dockerfile') }}
- name: Build and save docker image
run: |
if [ ! -f ~/caches/images.tar ]; then
docker build -t bucky-management . --build-arg rails_env=development && \
mkdir -p ~/caches && \
echo 'tar start'
docker save bucky-management -o ~/caches/images.tar
echo 'tar finish'
fi
run:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Cache restore
uses: actions/cache@v1
with:
path: ~/caches
key: ${{ runner.os }}-build-v3-after-${{ hashFiles('Dockerfile') }}
restore-keys: |
${{ runner.os }}-build-v3-${{ hashFiles('Dockerfile') }}
- name: Docker load
if: steps.cache.outputs.cache-hit != 'true'
run: |
docker load -q -i ~/caches/images.tar
- name: Create docker network and run and setup BM
run: |
docker network create bucky
docker-compose -f docker-compose.bucky.yml up --build -d
sleep 10
- name: Migrate and insert test data
run: |
docker exec -i bm-app rails db:create
docker exec -i bm-app rails db:migrate
docker exec -i bm-app rails db:fixtures:load
- name: Clone test codes
run: |
mkdir /opt/bucky-core
git clone https://github.com/hikimochi/bucky-testing.git /opt/bucky-core
- name: Run bucky-core
run: |
cd /opt/bucky-core
docker-compose up --build -d
sleep 5
- name: Execute testing
run: docker exec -i bucky-core bucky run -D pc -d -l $(cat $GITHUB_EVENT_PATH | jq -r '.pull_request.labels[].name')
jobs-build
Bucky-Managementイメージのキャッシュを作成しています。
Cache docker image of Bucky-Management
ここではBucky-Managementイメージのcacheを作っています。
テストを実行するときにプロダクトコードをマウントし、アプリケーションサーバを立ち上げる仕組みをとることでDockerfileを書き換えない限りは再ビルドしなくて済むようになります。
Build and save docker image
キャッシュヒットしないときはBucky-Managementコンテナをビルドし、特定のディレクトリにsaveしています。
jobs-run
実際にテストを実行するジョブです。
GitHub Actionsではneeds
を使うことでジョブの前後関係を作ることができます。
Cache restore
buildジョブで生成したcacheをリストアします。
Docker load
docker save
されたimageをloadします。
machineのimages内にbucky-managementという名前でloadされます。
Create docker network and run and setup BM
Bucky-Managementを立ち上げるためのネットワークを作成し、docker-composeでアプリケーションを立ち上げます。
ウェブサーバとしてnginx、データベースとしてmysqlコンテナを使います。
docker load
でbucky-managementイメージがローカルに展開されたので、image: bucky-management
で指定できるようになります。
Migrate and insert test data
データベースのマイグレーションとテストデータの格納を行います。
テスト実行の度にテストデータはきれいに作り直す仕組みをとっています。
Clone test codes
ここからはBucky-Coreでテストを実行するための準備を行っていきます。
テストコードをクローンします。
Run bucky-core
Bucky-Coreを実行するためにコンテナを起動します。
先程作成したネットワーク内で立ち上げることで、machineの影響を受けずcontainer_nameで名前解決できます。
Execute testing
実際にテストを実行する部分です。
bucky run -l [ラベル名]
で指定したラベルを持つテストを実行できます。
$GITHUB_EVENT_PATH
に関しては次で紹介します。
GITHUB_EVENT_PATH
GitHub Actions以外のCIツールではPull Requestのラベル情報をとってくるにはGitHub APIを使う必要があります。
GitHub ActionsではGITHUB_EVENT_PATHにそのビルドに関係する情報がjson形式で格納されます。
今回はその情報をjqで処理することで、ラベルの情報のみ取り出しています。
cat $GITHUB_EVENT_PATH | jq -r '.pull_request.labels[].name'
実際に使ってみる
ここではBucky-ManagementのTOP画面を改修したという想定です。
Pull Requestの作成時にラベルを付与します。
※本来のラベルとは違うラベルの使い方をしているのでラベルはテスト用だとわかるようにしたほうが良いと思います。例)「TEST: TOP」など
ビルドではこのように指定したラベルのみ実行されます。
今回使用したコードはこちらで管理してますのでよかったら参考にしてください。
今後の展望
今回はBucky-Managementをテスト対象としましたが、より大きな開発規模のものにおいては、QAと開発者のドメイン知識の差をラベルを通して埋めることにも繋げられると思っています。
プロダクトコードとラベルの対応をストアすることで、プロダクトコードが製品のどの領域(ラベル)に紐付いているかの情報が溜まっていきます。
QAは開発者に聞かなくてもある程度の情報はプロダクトコードとラベルの情報から得られることになります。
また、それを元に実行するテストを自動的に判別することも可能になります。
例えば、複数の開発者で修正が起こるfoo.rb
に対してラベルでの運用がある程度行われたとします。
ファイル名 | ラベル名 | 使用数 |
---|---|---|
foo.rb | TOP | 2 |
LIST | 18 | |
DETAIL | 80 |
このようなデータがある中で、ラベルが付与されていないPull Requestにおいてfoo.rbが改修されたときはDETAILのラベルがつくテストを実行する仕組みを作れば、修正ファイルに応じたテストの自動選択を実現することができます。
確率的に選べばより網羅的なテストができて良いかもしれませんね。
次回はこの仕組みを実際に構築した記事を書きたいと思います。
それでは良いお年を!