フロントエンドのカバレッジをslackに定期配信してみた
はじめに
こんにちは!株式会社POLでエンジニアをやっている @show_kanamaru です!
POLは「研究者の可能性を最大化するプラットフォームを創造する」をビジョンに、理系学生に特化した採用サービス、および研究開発者・技術者に特化した転職/採用サービスの2サービスを運営しています。
今回はフロントエンドカバレッジの可視化について書きたいと思います!
課題
みなさんはフロントエンドのカバレッジをどのように可視化してますでしょうか?
弊社ではbuild中にカバレッジを計測し、閾値を下回っていたらテストがコケるような運用をしていたのですが、カバレッジ出力をするとテストの実行時間が長くなってしまうこともあり、毎pushごとにカバレッジを計測する必要はないのではないかと判断し、buildのタスクからは外しました。
(詳しくはこちらのテックブログを見てみてください)
これでテストの実行時間は速くなったとはいえ、自分でコマンドを叩かないとカバレッジを見ることはできなくなってしまいました。
なので、今回はカバレッジを定期的にslackに配信してくれるシステムを作ってみました。
やったこと
1. カバレッジの閾値を設定
設定した閾値を下回ったらエラーを表示したいので、フロントエンドのプロジェクト直下にカバレッジの閾値を設定したjsonファイルを作成します。
coverage.json
※こちらは本番環境ではなく、検証環境の数字になります。
{
// 企業側のコード
"labbase_client": {
"Statements": 39,
"Branches": 44,
"Functions": 25,
"Lines": 38
},
// 学生側のコード
"labbase_compass": {
"Statements": 41,
"Branches": 22,
"Functions": 34,
"Lines": 40
}
}
2. カバレッジファイルを出力
POLではJestを使用しフロントエンドをテストを書いています。
Jestではテスト実行時に--coverageオプションを付けると、カバレッジを計測し、以下のようなファイルを作成してくれます。
それぞれの数字の意味はこちら
Statement
プログラム内の各命令が実行されたかの網羅率
Branches
ifやcaseなどの全ての分岐の処理が実行されたかの網羅率
Functions
プログラム内の各関数が呼び出されたかの網羅率
Lines
ソースファイルの各実行可能行が実行されたかの網羅率
こちらのファイルを出力するようにしておきます。
3. slackのWebhook URLを取得
今回はカバレッジをslackに定期通知したいので、Webhook URLを取得します。
こちらの記事を参考に取得してください。
4. スクレイピング
さきほどのファイルからスクレイピングをして、カバレッジの値を取得します。
output_coverage.py
import requests
import json
from bs4 import BeautifulSoup
class Slack:
def __init__(self):
self.url = 取得したWebhook urlを記載
def send_message(self, text):
requests.post(self.url, data=json.dumps({
"text": text,
"icon_emoji": ":cat:",
"username": "梅ちゃん"
}))
class CoverageThreshold:
def __init__(self):
self.coverage_thresholds = json.load(
open('../project/labbase_frontend/coverage.json', 'r'))
def get_thresholds(self):
return self.coverage_thresholds
class Scraping:
def __init__(self, service):
self.service = service
html_path = f'../project/labbase_frontend/coverage/{service}/lcov-report/index.html'
with open(html_path) as f:
res = f.read()
self.soup = BeautifulSoup(res, 'html.parser')
def get_coverage(self, coverage_thresholds):
text = f"*【{self.service}】*\n"
coverages = self.soup.find_all(class_='fl pad1y space-right2')
for coverage in coverages:
type = coverage.find(class_='quiet').get_text()
value = float(coverage.find(
class_='strong').get_text().replace("%", ""))
if (value >= coverage_thresholds[self.service][type]):
text += f":white_check_mark: {type}: {value}%"
else:
text += f":x: {type}: {value}%(基準値は{coverage_thresholds[self.service][type]}%です。テストコード足りないよ!)"
text += "\n"
text += "\n"
return text
if __name__ == '__main__':
# カバレッジの閾値取得
coverage_thresholds = CoverageThreshold().get_thresholds()
# labbase_compassのカバレッジ取得処理
compass_scraping = Scraping("labbase_compass")
compass_coverage = compass_scraping.get_coverage(coverage_thresholds)
# labbase_clientのカバレッジ取得処理
client_scraping = Scraping("labbase_client")
client_coverage = client_scraping.get_coverage(coverage_thresholds)
# slack投稿処理
slack = Slack()
slack.send_message(compass_coverage + client_coverage)
5. circleCIの設定ファイル修正
今回は、CircleCIのワークフローのスケジュール実行機能を利用して、毎日18時に定期配信しようと思います。
executors:
frontend_defaults:
docker:
- image: circleci/node:10-browsers
environment:
NODE_OPTIONS: --max_old_space_size=4096
python:
docker:
- image: circleci/python:3.9.0
jobs:
compass_frontend_coverage:
executor:
name: frontend_defaults
steps:
- checkout
- judge_job_execution:
target_directory: project/labbase_frontend/app/labbase_compass
- restore_frontend_setup
- setup_frontend
- run:
name: output labbase_compass_frontend coverage
command: cd project/labbase_frontend && npm run test:compass:coverage
no_output_timeout: 10m
- persist_to_workspace:
root: .
paths:
- project/labbase_frontend/coverage/labbase_compass/lcov-repor
coverage_to_slack:
executor:
name: python
steps:
- checkout
- attach_workspace:
at: .
- run:
name: install beautifulsoup4
command: sudo pip install beautifulsoup4
- run:
name: notify to slack
command: cd .circleci && python output_coverage.py
no_output_timeout: 10m
workflows:
version: 2
frontend_coverage:
triggers:
- schedule:
cron: "0 9 * * *"
filters:
branches:
only: /master/
jobs:
- compass_frontend_coverage
- client_frontend_coverage
- coverage_to_slack:
requires:
- compass_frontend_coverage
- client_frontend_coverage
注意点①
カバレッジ出力ファイルを他のjobでも使用するため、persist_to_workspaceを使う必要があり、そのファイルを参照するjobではattach_workspaceを使います。
注意点②
CircleCIは、タイムゾーンがUTCになっているため、日本時間で考える場合、実行したい時間から9を引いた値を設定する必要があります。
以上で準備完了です!
実際はこんな感じ
成功
失敗
ちなみに、梅ちゃんはメンバーが飼ってる猫の名前です。
おわりに
今回はフロントエンドのカバレッジをslackに定期配信してみました!可視化することで、メンバーのカバレッジ向上へのモチベーションアップに繋がればいいなと思っています!
そして、株式会社POLではエンジニア、デザイナー、プロダクトマネージャーを大募集してます!お話しだけでも構いませんのでお気軽にお声がけください!!!