はじめて CircleCI を触ったので、将来の自分用として作業メモ。
ずっと Jenkins で Docker コマンドを叩いてテスとしていた馬鹿らしくなる位、簡単にテストの設定や GitHub との連携が出来るので驚きました。
前提とする知識
本記事では
- Python における Unittest を用いたテストについて
- カバレッジなどテストにおける基本的な概念
の説明は割愛させていただきます。
テストトハナンゾヤ?ドウヤッテカクノダ?と言う方はまずそちらについての記事を読むことをお薦めします。
テストを行うリポジトリの準備
テストコードを準備
行うテストの内容も a と b を比較するだけの非常にシンプルなものです。
import unittest
class TestSample(unittest.TestCase):
def test_success_sample(self):
a = 1
b = 1
self.assertEqual(a, b, msg='a is not equals b')
if __name__ == '__main__':
unittest.main()
念のためローカルでテストを実行して問題ないことを確認しておきましょう
$ python -m unittest discover -s tests/
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
CircleCI の設定ファイルを記述
全ての設定項目について知りたい方は公式ドキュメントを参照してください。
今回はテストの実行しか行わないため、ほとんどの機能を使いません(笑)
CirclrCI の設定ファイルは .circlrci/config.yml
に設置されます。
ここに色々と設定を書けるのですが、今回使うのは
- version
- jobs
だけです。詳しくは公式ドキュメントのPythonでのサンプルを参照して下さい。
version の設定
version
はその名の通りバージョンを指定します。とりあえず 2
もしくは 2.1
を指定しておけば大丈夫かと思います。
jobs の設定
ここで、具体的にビルド、テスト、デプロイの手順を記述します。
最低限必要な物は以下の要素になります。
jobs:
build:
working_directory: [コンテナ内での作業ディレクトリ]
docker:
- image: [Dockerコンテナ名]
steps:
- checkout
- run:
command: |
[実行コマンド]
jobs
の後は、ジョブ名を指定します。今回、やっている事的にはtest
となるべきなのにジョブ名がbuild
になっていますが、これは build というジョブがないとエラーになるためです。 Python のようなビルドが不要な言語からすると、少し煩わしい仕様になっています。working_directory
では作業ディレクトリ名を指定します。分かれば何でも大丈夫です。今回の例では~/circleci-test
としています。docker -> image
では実際にビルドやテストが走るイメージを指定します。CircleCI 自体が CircleCI で使いやすいようにカスタマイズしたイメージを配布しているので、そちらを使うことをお薦めします。steps -> checkout
ではworking_directory
で指定した場所にリポジトリを checkout してきます。steps -> run
で指定したコマンドを実行します。今回はコマンドを1つしか実行しませんが、今後のことを考えて複数行受け取れるようにしています。(詳しくはYamlの仕様を参照して下さい。)
できあがり
最終的に次のような設定ファイルが出来上がります
気をつけて欲しい点として、 デフォルトだと /usr/local/bin
に PATH が通っていないので、python はフルパスで指定する必要があります。
version: 2.1
jobs:
build:
working_directory: ~/circleci-test
docker:
- image: circleci/python:3.7.3
steps:
- checkout
- run:
command: |
/usr/local/bin/python -m unittest discover -s tests/
これでリポジトリの準備は完了しました。が、まだ CirclrCI 側の設定が完了していないため GitHub への PUSH はしないでください。
CircleCI の Web での設定
一通り前準備が終わったので、今度は CircleCI の GUI を使って設定をしていきます。
Jenkins と違ってほとんどの設定をファイルに書くので、ここでの作業は本当に最低限のものになります。
アカウント作成
特に難しい所はないので説明は割愛します。
強いて言うと、 自分のリポジトリのあるサービスと連携してアカウント作っておくと、その後が楽になると思います。
監視するリポジトリを設定
まず、右側のメニューから「Setting」を選び、サブメニューから「Projects」を選びます。
すると、こんな感じの画面になるはずです。(circleci-test 以外は私が実際に使っているリポジトリなので無視してください)
今回は circleci-test というリポジトリをテストで作っているので、その設定を行うため、歯車マークをクリックします。
色々複雑な設定も出来ますが、今は未だ早いです。とりあえず、水色の「Follow Prject」を押しましょう
これで、プロジェクトが push された際、自動でビルド(今回の場合はテスト)が走るようになります。
Jenkins と違ってとても楽ですね…!
試しに push してみる
先ほど作ったリポジトリを GitHub に Push してみましょう。
少し待つとテストが始まり…
無事テストが通りました!
おまけ: Coverage を取得する
ここまでで、基本的にテストを行う設定は完了です。が、カバレッジは取得したいですよね?ですよね?
ついでにその設定を行ってみましょう。
とりあえず、カバレッジを取得するため、以下のようなファイルを作成します。
def add(a: int, b: int) -> int:
return a + b
def mul(a: int, b:int) -> int:
return a * b
そして、テストも次のように書き換えます
import unittest
from sample import add
class TestSample(unittest.TestCase):
def test_success_sample(self):
self.assertEqual(add(1, 2), 3, msg='function add is invalid')
if __name__ == '__main__':
unittest.main()
config.yml
を設定するのですが、ほぼ公式ドキュメントのPythonでのサンプル に書かれているので、結果だけ書きます。
以下の設定ファイルで Coverage が取得できるようになります。
Coverage のオプションについては、本筋からそれるのでここでは解説しません。Coverage.py の公式ドキュメントを参照して下さい。
本当は pipenvなどを使った方が今風だと思うのですが、そこまでやる必要もないテストなので、直接 /usr/local/bin 以下にパッケージをインストールします。
version: 2.1
jobs:
build:
working_directory: ~/circleci-test
docker:
- image: circleci/python:3.7.3
steps:
- checkout
- run:
command: |
sudo chown -R circleci:circleci /usr/local/bin
sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
pip install coverage==5.0a5
- run:
command: |
coverage run -m unittest discover -s ./tests
- store_test_results:
path: result.xml
ついでに、ローカルでデバッグしていると色々ファイルが生成されるので、 .gitignore
ファイルに入れておきましょう。
.coverage
htmlcov/
これで準備は整いました、PUSHしてみましょう。
すると、テストの終盤、色々アップロードがはじまって…
Artifacts のタブから HTML でのカバレッジが確認出来るようになります!(沢山ありますが、index.html
が本体です)
これで、どこのテストを書いていないかが一目で分かるようになります。
ホントのおまけ: .coveragerc に設定を分離
最後に、coverage のオプションは .coveragerc
に分離した方が、オプションが長くなった際に管理が楽なので、そちらに移動させましょう。
次のようなファイルを作成します。
[run]
command_line = -m unittest discover -s ./tests
[report]
omit = */tests/*,*/venv/*
これで、run, report 時のオプションを省略できるようになります。
version: 2.1
jobs:
build:
working_directory: ~/circleci-test
docker:
- image: circleci/python:3.7.3
steps:
- checkout
- run:
command: |
sudo chown -R circleci:circleci /usr/local/bin
sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
pip install coverage==5.0a5
- run:
command: |
coverage run
coverage report
coverage html
- store_artifacts:
path: htmlcov
これで PUSH してみましょう。先ほどと同じ結果が得られるはずです。