この記事のまとめ
- テストの分類に関して、Small・Medium・Largeを理解し、チーム内で認識を合わせる
- テストの比率はSmall : Medium : Large = 7 : 2 : 1
- テストのカバレッジの目標は70%
- テストの実行時間は10分以内
- 1,000行当たりのテストケース数(参考)
- Small: 112.0 ~ 181.0
- Medium: 32.0 ~ 51.7
- Large: 16.0 ~ 25.9
自動テストの実践と責任
プロダクトの開発が辛い。バグを直したら、他の場所がバグる。何もしていないのに壊れる。前任者のコードの意図が読めなくて触れない。触れないから改修できない。しかし、機能追加の要望は上がってくる。仕方なく、機能追加したら既存の機能がバグって怒られる・・・しかも、そういったバグった機能は実は古くから居たユーザーの古の仕様で、大事にしたほうが良いユーザーの機能だったのに、明文化されていない仕様に後任者が嵌められ、恨み節を吐く。まぁ現場ではよくある話だったりします。
そんな時に、「手動でテストを全部網羅するのは無理!!既存の機能を自動でテストを回せる環境にするんだ!!CIを整備するんだ!!」と意気込むかと思います。そうすると、企業の論理で、「で、それってどれくらいやるのが最適なの?」「コストはどれくらい?」みたいなことを聞かれると思います。「自動テストを推進したい!」といった手前、そういった「自動テストに関する目標の設定」なども任されることもあるでしょう。
しかし、自分が「自動テストの環境を整えたい!!」と言っているレベルの話の時、実はそこまで自動テストに関する知見もなく、手あたり次第始めてしまいたい。という気持ちもあるでしょう。その中で、適切な目標設定というものも難しい問題となります。この目標設定は、本来企業のビジネスモデルと合致したものを選ぶべきではあります。しかし、1つの指標として、どれくらいテストを書けばよいか?どんなテストを書けばよいか?という方針や数値目標の基準を書いていきたいと思います。
テストの分類
以前にも、私はテストの分類について書いています。
最終的に一番使い勝手が良い。わかりやすい定義は、
- Small
- Medium
- Large
という分類です。
元ネタはGoogle Testing BlogのTest Sizeです。
サイトの表を整理すると
| 要素 | Small | Medium | Large |
|---|---|---|---|
| ネットワークアクセス | × | ローカルのみ | 〇 |
| データベース | × | 〇 | 〇 |
| ファイルシステム利用 | × | 〇 | 〇 |
| 外部システム利用 | × | 非推奨 | 〇 |
| 複数スレッド | × | 〇 | 〇 |
| Sleep関数 | × | 〇 | 〇 |
| システムプロパティ | × | 〇 | 〇 |
| 実行時間(秒) | 60 | 300 | 900+ |
非常に明瞭な基準で、Smallであれば、基本的にネットワークアクセスやデータベースなどを利用してはいけません。本当に純粋なロジックのみで、1件当たり60秒未満が推奨です。
Mediumでは、ネットワークアクセスはローカルのみに閉じるように構築します。外部システム利用は非推奨で、1件当たり、300秒未満にします。外部システム利用とは、平たく言うと、「今回の表に乗っている以外のシステム」となります。例えば、サードパーティーのWebAPIだったり、S3などのクラウドストレージも対象に入ります。一方で、データベースに関しては、ローカルネットワークにSQLサーバーを立てたりする分にはOKです。しかし、(あまりないと思いますが)テスト環境からAmazonRDSなどにつなぐようなケースは非推奨である。ということになります。
Largeは全てのシステムを利用してよいテストになります。1件当たり時間も900秒を超えても致し方なし。ということです。
今回、この章を書く予定はありませんでした。しかし、「会社において実務で自動テストを行う」ということを考えると、「テストの分類」「テストの粒度感」「テストの定義」をチーム内で認識の共有を行っておかないと、今後のテストの開発運用・一貫性の保持が難しくなる。 という実感があります。
これは、自分が新卒だった時の経験ですが、3つのWebAPIで構成されるシステムを行っていました。それぞれのAPIを動かし、手動テストを行っていました。3つのWebAPIが完成したので、これらを連携したテストを行う。ということになりました。その時に、私は、
「ちょっとまってください。これって、何テストなんですか?完成したWebAPIをテストすることは単体テストで、3つ連携したテストは結合テストって呼ぶんですか?でも、モジュール単位のテストも単体テストって呼んだり、データベースを使ったテストって結合テストって呼びません?そう考えると、単体テストや結合テストって二重の意味が含まれません?」
みたいなことを言った記憶があります。こんなことを考え始めると、かなり混乱すると思います。当時の会社の用語、チームの用語では、このような複数のシステムを連携したテストはスモークテストやシステムテストという用語が使われていました。
今回、Small、Medium、Largeという定義を書きましたが、「単一のソフトウェアに関してのテストの定義」と捉えてもらえるとよいです。今、混乱した例に挙げたような、「複数のAPIが連携したテストでの定義」ではない。ということを覚えておいてください。
まずは、このSmall, Medum, Largeと呼ばれる「単一のソフトウェアに関してのテストの定義と範囲」の共通理解をチームで持つことで、チーム内のテストに対する混乱を防ぎ、それぞれの制約を一貫して守ることが大事です。
テストの比率
先ほどの章では、テストはSmall, Medium, Largeという種類があることについて書きました。では、どのテストをどれくらい書けばよいのでしょうか。
テストの比率は、Small : Medium : Large = 7 : 2 : 1です。
元ネタはGoogle Testing BlogのJust Say No to More End-to-End Testsです。
もともとは「E2Eテスト : 結合テスト : ユニットテスト = 1 : 2 : 7」という記載でした。ここでは、Small/Medium/Largeに表記を変えています。
おおむね、
ユニットテスト = Small
結合テスト = Medium
E2Eテスト = Large
の認識で私は良いと思います。例えば、フロントエンドにおいてPlaywrightでテストを書く。となると、おおむねE2Eテストと呼ばれると思います。それは、Largeの分類に入る。と認識してOKです。実際、Playwrightという外部ツールやブラウザなどの外部システムに依存したシステムであるため、Largeといっても差支えはないと思います。他にも、WebAPIをテストする際に、実際にHTTP ClientでHTTPリクエストを行い、その機能を確認するのは、E2E的なテストになります。これらのテストは、Webサーバーなどのミドルウェアを利用する場合もありますし、ネットワークを介する場合もあります。サーバーとクライアントの間にロードバランサーが含まれている場合もあるかもしれません。そうするとロードバランサーという外部システムやネットワーク構成も絡み合うため、Largeという分類でも問題ないでしょう。そのため、E2Eテスト=Largeと言ってもそこまで問題はないと思います。
テストのカバレッジの目標
SmallやMedium、Largeの定義は分かった。そして、それがどれくらいの比率で書くべきかの基準も分かりました。しかし、一方で一番わかりやすい基準として、テストのコードの網羅率、カバレッジがどれくらいか?ということは定量指標として測りやすい基準になります。私なりの基準としては、
コードカバレッジが70%を目標
にするとよいと認識しています。
これは、最近執筆させていただいたWeb API開発実践ガイドにも、そう書きました。
元ネタは、Google Testing BlogのMeasuring Coverage at Googleです。
一部抜粋すると
Google全体で測定された絶対カバレッジの平均値のヒストグラムです。コードカバレッジの中央値(50パーセンタイル)は78%、75パーセンタイルは85%、90パーセンタイルは90%です。これらの数値は、非常に健全なコードベースを表していると考えています。
となっています。Googleの中央値で78%程度のカバレッジだ。ということです。なので、これからテストを整備するぞ!という目標に対しては、70%は思ってるよりかは高い目標です。実際にテストが未導入の環境から70%のカバレッジにするのは、かなりの努力が必要です。ちゃんと自動テストを行う仕組みを作らないと、カバレッジが50,60%で止まり、網羅率がなかなか上がらないことも多い感触があります。いやいや、そうじゃないだろう。78%ぐらい簡単だろう。みたいなことを言ってくる人(主に上司)がいると思います。そのためのカウンターとして、「Googleぐらい給料もらってたらカバレッジ78%ぐらいできるかもしれませんけど、それくらい給料出してます?」って言うと黙らせられると思います。 懐刀として持っておくには強いロジックですが、強い力にはそれなりに責任を伴うこともあるので注意が必要です。
テストのケース数
これまでの内容で、どのようなテストの種類があり、どれくらいの割合で書けばよくて、コードカバレッジの目標値もわかりました。では、テストのケース数はどうでしょうか?コードカバレッジが70%あればよいでしょうか?個人的にはYesで、テストケースが多ければ、比例してカバレッジが多くなるでしょうし、テストケースが少なければ、カバレッジが低くなるでしょう。そのため、テストケース数自体を追うより、カバレッジを追う方がソフトウェア開発の品質管理の現状を表しているような気はしています。
このテストケースに関する統計情報もあります。独立行政法人情報処理推進機構のソフトウェア開発分析データ集2022です。
表 5-1-1 SLOC 規模あたりのテストケース数[件/KSLOC]、検出バグ数(全開発種別)のデータを抜粋すると、
| N | 最小 | P25 | 中央 | P75 | 最大 | 平均 | 標準偏差 | |
|---|---|---|---|---|---|---|---|---|
| 結合テスト(テストケース) | 665 | 0.0 | 22.2 | 51.7 | 120.1 | 100,000.0 | 484.9 | 4,821.2 |
| 総合テスト(テストケース) | 620 | 0.0 | 6.4 | 16.0 | 40.7 | 219,000.0 | 653.9 | 9,799.1 |
となっています。今回は、結合テストと総合テストの中央値を参考にしたいと思います。理由としては結合テストに関する以下の図があります。
横軸の点がテストケースを表していますが、KSLOC(ソースコード1,000行)あたりのテストケース数が100以下に多く分布していること。また、平均値を見てみると484.9とあまりにも中央値との乖離があります。これは、最大値が100,000件というとてつもない値により引き上げられています。これは1行あたり100件のテストがあることになっています。そのため、結合テストのテストケース数の中央値である51.7[ケース/SLOC]を考えます。
また、総合テストの方はどうかというと、同じように図を見てみます。
これを見てみると、同様に横軸が100以下の値に集中しているため、代表値としては中央値の16.0を取るのが妥当かと判断しました。
これらのデータですが、もともとは、ソフトウェア開発データ白書2018-2019のデータです。ここに詳しい定義が書かれています。
テストケース数(データ項番:5251、5252)
5251, 1005_結合テスト
結合テストケース数(5251)、結合テストケース数定義(1005)
5252, 1005_総合テスト(ベンダ確認)
総合テストケース数(5252)、総合テストケース数定義(1005)
結合テスト
開発者は、ソフトウェアユニット及びソフトウェアコンポーネントを結合して、ソフトウェア品目にするための計画を作成し、ソフトウェア品目を完成させる。また、結合及びテストを行う。完成したソフトウェア品目と合わせてハードウェア品目、手作業や他システム等とあわせてシステムに結合、要件を満たしているかをテスト、システム適格性確認テスト実施可能状態であることを確認する。必要に応じて利用者文書等の更新を行う。テストの評価と共同レビューを実施する。
総合テスト(ベンダ確認)
開発者は、ソフトウェア品目の適格性確認要求事項およびシステムに関して指定された適格性確認要求事項に従って、適格性確認テストおよび評価を行う。必要に応じて利用者文書等の更新を行う。また、監査の実施と支援をする。
このような定義となっているため、結合テスト=Medium、総合テスト(ベンダ確認)=Largeと捉えて、計算してみましょう。
結合テストベースで考えると、
Small : Medium : Large = 7 : 2 : 1 = 181.0 : 51.7 : 25.9
総合テストベースで考えると
Small : Medium : Large = 7: 2 : 1 = 112.0 : 32.0 : 16.0
となります。したがって、それぞれのテストのタイプにおけるテスト数は以下のような基準になります。
| 種別 | 1,000行当たりのテストケース数 |
|---|---|
| Small | 112.0 ~ 181.0 |
| Medium | 32.0 ~ 51.7 |
| Large | 16.0 ~ 25.9 |
| 合計 | 160.0 ~ 258.6 |
データをベースに話していますが、所感としては結構多いかな。という印象です。
仮にですが、先ほどのGoogleのカバレッジの中央値78%を考えます。そうすると、
160.0 / 0.78 ≒ 216.7
258.6 / 0.78 ≒ 331.5
全てのテストケースの数は216.7~331.5件あるはずです。
例えば、if文を考えたとき、コードとしては2つへ分岐します。2の8乗が256、2の9乗が512です。ということは、単純に考えると、if文が8つのテストケースは256のテストケースがあり、9つの場合はテストケースが512件あります。そう考えると、1,000行当たり8~9個のif文が出てくる。といったことになります。
本当かな?と思って、https://ai-coding.info のソースコードをgrepで雑に解析してみたところ1,000行当たり13行のif文が存在しました。そのため、if文の数ベースでは、まんざら大外れではない気がします。
ただし、この議論は全条件を網羅する話をしており、一般的なカバレッジはC0の命令網羅をベースとした値となっています。ではC0カバレッジで、同様にif文で分岐をするように考えると、4~6行に1回if文が発生する計算になります。これは現実的ではないです。
このデータは割と解釈が難しく、以下のような図もあります。
実は、そもそもカバレッジを計測しているプロジェクトが32.6%しかおらず、その中での議論をしています。そして、その計測しているプロジェクトは、条件網羅のカバレッジ(C2)が100%のプロジェクトが52.9%いる。というなかなかすごい母集団のデータになっています。したがって、この調査においては、カバレッジを計測しているようなプロジェクトは、ものすごくカバレッジが高い。という話が大前提にあります。
そのため、このあたりのテストケースの数に関しては、割と参考程度にしておくとよいと思います。
テスト実行時間
テストの分類が終わり、どれくらいの比率で書けばよいか分かりました。テストのカバレッジや、テストケースの数も多少参考になる数字が分かりました。では、自動テストの実行時間はどれくらいかけるべきでしょうか?
自動テストのテスト実行時間は10分以内にすべきです。
これは、エクストリームプログラミングという本に書かれているプラクティスに「10分ビルド」というものがあります。
自動的にシステム全体をビルドして、すべてのテストを10分以内に実行させること。ビルドに10分以上かかるようだと使用頻度が減り、フィードバックの機会が失われてしまう。ビルドが短縮できれば、途中でコーヒーを飲むこともない。
これは根拠が薄弱ではありますが、1つの基準として、ビルドとテストが合わせて10分以内に終わること。ということが目安とされています。そのため、テストに100%時間を使ったとしても、最大10分程度を目安にした方がいい。ということになります。
まとめ
- テストの分類に関して、Small・Medium・Largeを理解し、チーム内で認識を合わせる
- テストの比率はSmall : Medium : Large = 7 : 2 : 1
- テストのカバレッジの目標は70%
- テストの実行時間は10分以内
- 1,000行当たりのテストケース数(参考)
- Small: 112.0 ~ 181.0
- Medium: 32.0 ~ 51.7
- Large: 16.0 ~ 25.9
自動テストの落とし穴と解決方法
自動テストの落とし穴として、実際のプロダクトでテストを書いてみたとき、「結構、書けない。」ということが起こります。この言語化は難しいのですが、おおむね単体テスト、Smallなテストが書けず、結合テスト(Medium)やE2E(Large)テストが多くなっていまいがちです。そうするとテストシステム自体が不安定化し、先ほどの1:2:7の割合を守れなくなってきます。しかし、この結合テストやE2Eテストを単体テスト化することに一芸必要だったりします。その結合・E2Eテストをどのようにすれば単体テスト化できるのか。というあたりを書いた文章もありますので、良ければご覧ください。
感想
たまたま1年ぶりぐらいに知り合いからメッセージが来て、話をすることがありました。一緒に仕事をしていた時期もあり、二人三脚でテストの環境を整備していた時期もありました。そんな折に、テストってどこまで書けばいいんですかねーみたいなことを聞かれて、まぁ、あれを参考にしたらいいよ。みたいなことを一言二言、言ったのですが、そういえばテストに関する定量的な指標って、まとめられてないし、意外に需要があるのかなーと思って書きました。いわゆるチートシートのようなものとして引き出しに入れておいて、興味があったり、なんでそうなんだっけを後からじっくり見れるようなことを意識して書きました。割と久々にテストについて語った気がする。





