見出し画像

フロントエンドのカバレッジをslackに定期配信してみた

はじめに

こんにちは!株式会社POLでエンジニアをやっている @show_kanamaru です!

POLは「研究者の可能性を最大化するプラットフォームを創造する」をビジョンに、理系学生に特化した採用サービス、および研究開発者・技術者に特化した転職/採用サービスの2サービスを運営しています。

画像1

今回はフロントエンドカバレッジの可視化について書きたいと思います!

課題

みなさんはフロントエンドのカバレッジをどのように可視化してますでしょうか?

弊社では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オプションを付けると、カバレッジを計測し、以下のようなファイルを作成してくれます。

画像3


それぞれの数字の意味はこちら

Statement
プログラム内の各命令が実行されたかの網羅率

Branches
ifcaseなどの全ての分岐の処理が実行されたかの網羅率

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を引いた値を設定する必要があります。


以上で準備完了です!


実際はこんな感じ

成功

画像4

失敗

画像4

ちなみに、梅ちゃんはメンバーが飼ってる猫の名前です。


おわりに

今回はフロントエンドのカバレッジをslackに定期配信してみました!可視化することで、メンバーのカバレッジ向上へのモチベーションアップに繋がればいいなと思っています!

そして、株式会社POLではエンジニア、デザイナー、プロダクトマネージャーを大募集してます!お話しだけでも構いませんのでお気軽にお声がけください!!!


この記事が気に入ったらサポートをしてみませんか?