Help us understand the problem. What is going on with this article?

テストカバレージを計測して内容を見てみよう

はじめに

この記事はPonos Advent Calendar 2019 20日目の記事です。

ポノスでは月に一度を目標に全社のエンジニアを集めて社内勉強会を開催しています。
こちらはその全社勉強会の資料になります。

せっかく勉強会のために資料を作るのなら公開を前提にして作成してみようということでQiitaで資料を作成してみました。

尚、この資料を利用した社内勉強会は12月16日に開催されました。

テストカバレージを計測して内容を見てみよう

ユニットテストについての話はよく耳にされているかと思います。

テストがないプロジェクトにテストを追加したり
新しいプロジェクトでテスト駆動開発を取り入れてみたりすることは非常に意義があることだと思います。

以下は一例ですがユニットテストを取り入れる際になぜそれを実施したいのかは明白だと思います。
・バグを減らしたい
・関数の入力値と出力値を保証したい
・コード修正が他に波及していないかどうかを判定する仕組みを作りたい
・CI/CDパイプラインを構築するための基礎となるため
 等々

プロジェクト全体(ソースコード全体)を俯瞰した場合、
上記の目的で導入したテストは何をどの程度実施しているのでしょうか?

これを確認するための一つの指標としてテストカバレージというものがあります。

以下にテストの例を載せます。
(以下はnode.jsのアプリケーションのユニットテストの例です。
ユニットテストとテストカバレージの計測にはjestを利用しています。)

> jest

 PASS  test/model/command_results.test.js
 PASS  test/runner/http.test.js
 PASS  test/runner/snmp.test.js
 PASS  test/model/command_result.test.js
 PASS  test/runner/ping.test.js
 PASS  test/helper/command_runner.test.js (6.156s)

Test Suites: 6 passed, 6 total
Tests:       20 passed, 20 total
Snapshots:   0 total
Time:        8.692s, estimated 16s
Ran all test suites.

上記のコンソール出力結果は詳細出力とテストカバレージの計測を行っていません
この結果から読み取れるのは
・設定したユニットテストが全てパスしていること
・ユニットテストの実施にかかった時間
・ユニットテストの個数
・どのファイルがユニットテストされたのか?(ただし網羅されているかどうかは分からない)
です。

これでは
・どんな項目が具体的にテストされたのか?
・どの程度、テストされたのか?
が分かりません。

このままだとシステム全体の規模が大きくなればなるほど適切にユニットテストが追加されているのか不安になります。


一方で下記のコンソール出力結果は詳細出力とテストカバレージの計測を行っています
こちらからは以下が追加で読み取れます。
・具体的に何がテストされたのか(verboseオプション)
・コードのどの部分は少なくともテストケースがなめているのか?(coverageオプション)
 ・全ての条件分岐(if文等)がユニットテストで網羅されているのか?等
 ・Jestの各種パラメータの説明は以下になっています。
  ・Stmts: 命令網羅
  ・Branch: 分岐網羅
  ・Funcs: 関数が網羅されているかどうか
  ・Line: ソースコードの各行が実行されたかどうか
  (https://stackoverflow.com/questions/26618243/how-do-i-read-an-istanbul-coverage-report
   https://www.guru99.com/code-coverage.html)

この情報はプロジェクトに関わるエンジニアの数が増えるほど、プロジェクトの規模(コードの量)が増えれば増えるほど効果を発揮するのではないかと思います。

> jest "--verbose" "--coverage"

 PASS  test/model/command_results.test.js (10.608s)
  ✓ can init. (6ms)
  ✓ can update. (1ms)
  ✓ can not update without init. (1ms)
  ✓ can be json formatted value. (1ms)
  ✓ can be csv formatted value.

 PASS  test/runner/http.test.js (11.248s)
  ✓ can not be reached to a nonexistance url of a http protocol (97ms)
  ✓ can not be reached to a nonexistance url of a https protocol (33ms)
  ✓ can be reached to an existance url of a http protocol (456ms)
  ✓ can be reached to an existance url of a https protocol (189ms)

 PASS  test/model/command_result.test.js
  ✓ function isOK works fine (1ms)
  ✓ function message works fine (1ms)
  ✓ this model can be string

 PASS  test/runner/snmp.test.js
  ✓ can be reached to an open snmp server (133ms)
  ✓ can not be reached to an unknown host (15ms)

 PASS  test/helper/command_runner.test.js (15.038s)
  ✓ can be reached to an open snmp server by using CommandRunner (1163ms)
  ✓ Result of dry-run should be true (1002ms)
  ✓ Result of an undefined command should be false (1006ms)
  ✓ Result of an exception in an existing command should be false (1078ms)

 PASS  test/runner/ping.test.js
  ✓ can be reached to a localhost (24ms)
  ✓ can not be reached to an unexistence ip address (2029ms)

---------------------|----------|----------|----------|----------|-------------------|
File                 |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------------|----------|----------|----------|----------|-------------------|
All files            |    87.13 |    72.22 |    81.58 |    88.78 |                   |
 helper              |      100 |      100 |    91.67 |      100 |                   |
  command_runner.js  |      100 |      100 |      100 |      100 |                   |
  logger.js          |      100 |      100 |    83.33 |      100 |                   |
 model               |    65.71 |    33.33 |    64.71 |     69.7 |                   |
  command_result.js  |      100 |      100 |      100 |      100 |                   |
  command_results.js |    58.62 |    33.33 |    53.85 |    62.96 |... 41,42,43,45,46 |
 runner              |    97.37 |     87.5 |      100 |    97.37 |                   |
  http.js            |    94.12 |       75 |      100 |    94.12 |                24 |
  ping.js            |      100 |      100 |      100 |      100 |                   |
  snmp.js            |      100 |      100 |      100 |      100 |                   |
---------------------|----------|----------|----------|----------|-------------------|
Test Suites: 6 passed, 6 total
Tests:       20 passed, 20 total
Snapshots:   0 total
Time:        31.021s
Ran all test suites.

ユニットテストそのものは人が記載するものなのでバグが入る余地があります。
そのため、カバレージの計測結果そのものを過信するのは禁物ですがプロジェクト全体からコードの全体像を俯瞰する一つの指標としては役に立ちます。

コードレビュー等を通してユニットテストの品質を維持することができればテストカバレージの計測は次のテストを設計するための良い指標/指針になるでしょう。

より具体的にテストカバレージについて知りたい方は
テストカバレッジ100%を追求しても品質は高くならない理由と推奨されるカバレッジの目標値について
ホワイトボックステストにおけるカバレッジ(C0/C1/C2/MCC)について
等を読むと良いでしょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした