きっかけ
これまでもTravis CIを使ってきていて、それ自体にはそんなに戸惑うことは無かったんですが、カバレッジも取得したくなったりしたので少し調べたら日本語情報があまりなかったのでここに残しておくことにしました。
環境
開発環境は以下
必要なPythonモジュールなど
- nose 1.3.7
- codecov 2.0.15
- coverage 4.5.1
各種サービスのセットアップ
Travis CI
Circle CIがどうにも複雑に見えてしまいずっとTravisを使っているため、今回もTravisです。
特に難しいところはなく、普通にサインアップしてCIしたいリポジトリを有効にするだけです。Build only if .travis.yml is present
にチェックを入れておくと良いと思います。
また、シークレットなトークンを暗号化するのに使うtravis
というコマンドをgem
でインストールします。
$ gem install travis $ travis login
.travis.ymlの文法エラーでCIをパスできないとめちゃくちゃ悲しくなるのでlint
コマンドを覚えると良いと思います。
$ cat .travis.yml language: python python: - "3.5" - "3.6" script: - nosetests -v $ travis lint Hooray, .travis.yml looks valid :)
Codecov
Codecovはカバレッジを表示してくれるWebサービスです。Pythonにはcodecov
というpipでインストールできるモジュールがあります*1。
同様のサービスとしてCoverallsなどがありますが、あまりデザインが好みで無かった上、Python用のパッケージが2種類あってうーんという感じだったのでこちらにしました*2。
上記リンクから、Githubアカウント、Gitlabアカウント、Bitbucketアカウントでサインアップできます。それぞれのオンプレ版にも対応しているみたいなので、かなり良さそうです。また、Teamでの使用もパブリックリポジトリなら無制限?のようです。プライベートリポジトリでの利用を検討している場合はリポジトリごと、またはユーザ数単位での課金になるようです*3。
有効にするリポジトリを選択するとトークンが表示され、カバレッジリポートのアップロードをしろみたいな画面になりますが、Travis CIから使うなら無視して良いです。
設定はもう終わりです(すごい)。
リポジトリのセットアップ
テストする
僕はずっとnoseを使っているので、今回もこれで行きます。フォルダ構成は以下の様にしました。student_portal_crawler
が今回テストするモジュールです。
$ tree -L 3 -I venv . ├── LICENSE ├── README.md ├── requirements.txt └── student_portal_crawler ├── __init__.py ├── browser.py ├── page ├── parser └── test ├── __init__.py └── test_script.py
noseのインストールおよびテスト実行は下記の様にします。テストの書き方についてはここでは解説しません。
$ pip install nose # テストの実行 $ nosetests ............................. ---------------------------------------------------------------------- Ran 20 tests in 0.680s OK # テストの実行とカバレッジの計算 $ pip install coverage $ nosetests --with-coverage
このままでは使用しているモジュール全てのカバレッジを取得してしまうので、--cover-package
オプションで取得するモジュールを指定してやります。今回の場合はstudent_portal_crawler
になります。
$ nosetests --with-coverage --cover-package=student_portal_crawler ............................. Name Stmts Miss Branch BrPart Cover --------------------------------------------------------------------------------------- student_portal_crawler/__init__.py 1 0 0 0 100% student_portal_crawler/browser.py 20 0 2 0 100% student_portal_crawler/page/__init__.py 1 0 0 0 100% student_portal_crawler/page/base.py 34 4 6 1 78% student_portal_crawler/parser/__init__.py 4 0 0 0 100% student_portal_crawler/parser/base.py 38 0 10 0 100% student_portal_crawler/parser/lec_info.py 18 0 6 0 100% student_portal_crawler/parser/static.py 5 0 0 0 100% student_portal_crawler/parser/utils.py 9 0 2 0 100% student_portal_crawler/shibboleth_login/__init__.py 1 0 0 0 100% student_portal_crawler/shibboleth_login/login.py 53 2 8 0 97% --------------------------------------------------------------------------------------- TOTAL 184 6 34 1 95% ---------------------------------------------------------------------- Ran 29 tests in 0.319s OK
.travis.ymlを書く
シンプルにPythonのバージョンいくつかでテストし、パスしたらCodecovにカバレッジを送信、Slackに結果を通知します。
まずは自分のSlackのIntegrationからTravis CI
を追加します。Hubotとかで節約している人も居るかとは思いますが、僕は面倒なので豪華に行きます。
追加したら投稿するチャンネルを決め、トークンを取得します。
Travis CIでの使い方についての説明の中に、トークンの暗号化についての項目があるのでコピペして実行します。事前に.travis.ymlがないとエラーが出るので作成しておきます。
$ touch .travis.yml $ travis encrypt "{{チーム名}}:{{トークン}}" --add notifications.slack $ cat .travis.yml notifications: slack: secure: npdNlesznnxrC7KsuB7....
Travis CIで利用可能なPythonバージョンは複数有り、最新は3.8-dev
やnightly
まで使える*4ようなのですが、
Recent Python development branches require OpenSSL 1.0.2+. As this library is not available for Trusty, 3.7-dev, 3.8-dev, and nightly do not work (or use outdated archive).
という記述があり、どうやったら使えるのか分からず3.6-dev
までしか使っていません…*5
最終的に下記の様にしました。
language: python python: - "3.5" - "3.5-dev" - "3.6" - "3.6-dev" install: - pip install -r requirements.txt - pip install codecov coverage script: - nosetests -v --with-coverage --cover-package=student_portal_crawler after_success: - codecov notifications: email: false slack: secure: npdNlesznnxrC7K...
after_success
でcodecov
コマンドを実行することで、Codecovにカバレッジリポートが送信されます。トークンなどを加える必要は有りません。
また、Slackへの通知のみで十分なのでメール通知はオフにしています。
.coveragercを書く
このままではテストコードまで含めたカバレッジがcodecovに表示されてしまったり、テストしないコード(デバッグ用のステートメントなど)まで含まれてしまうため、.coveragerc
という設定ファイルを置いて制御します。
[run] branch = True source = student_portal_crawler [report] exclude_lines = if TYPE_CHECKING: if __name__ == .__main__.: ignore_errors = True omit = student_portal_crawler/test/*
typing
モジュールを使用して型ヒントの定義をしているので、常にFalse
となり実行されないif TYPE_CHECKING:
という文が所々に現れるのでこれを排除しています。
また、実際の実行コード(if __name__ == '__main':
)も排除しています。
READMEへバッジを貼る
CI回してカバレッジ取得する最大の目的といっても過言ではない、READMEへのバッジを貼ります。
Travis CI
https://travis-ci.org/ユーザ名/リポジトリ名
にアクセスし、リポジトリ名の横に表示されているバッジをクリックすると、形式を選択してコピーできます。
Codecov
https://codecov.io/gh/ユーザ名/リポジトリ名/settings/badge
にアクセスすると形式を選択してコピーできます
後はpushすればCIが走ります。
結果を確認
Githubへpushしてしばらく待つとテストが完了します。
こんな風にSlackに通知が来ます。
Codecovに自動でカバレッジが送信され、以下の様に表示されます。
また、リンクを開いていくとどのモジュールのカバレッジが低いのか丸わかりな上、各ファイルのどの行がテストされていないのかも一発で分かります。
まとめ
取り扱いが面倒なことが多いトークン等の設定が必要ないため、Codecov + Travis CIはなかなかオススメの組み合わせかと思います。
どんどんunittestを書いて徳を積んでいきましょう!