📑

プロダクトのフェーズ別に見るテストカバレッジへの取り組み

に公開

(本記事は、Nstockメンバーの retu・tanakiyo・kakkie による共同執筆です。)

はじめに

Nstockでは、現在、株式報酬SaaSとセカンダリー(非上場株式の取引所)という2つのプロダクトを開発しています。株式報酬SaaSはリリースから約2年経ち、本番運用が始まっている一方、セカンダリーはまだリリースはしておらず、立ち上げの最中です。


株式報酬SaaSとセカンダリー

先日、バックエンドAPIのテストカバレッジについて話す機会がありました。その中で、カバレッジに対する考えは両チームで同じながらも、カバレッジ取得の背景やカバレッジ基準を満たすまでのアプローチが異なることに気がつきました。

既存プロダクトである株式報酬SaaSと新規プロダクトであるセカンダリーのテスト戦略の違いは、他のチームにとっても参考になるのではないかと考え、本記事で事例として紹介することにしました。

なお、本記事ではカバレッジ(網羅率)を主要なテーマとしており、テストの設計手法などについては詳しく取り上げておりませんのでご了承ください。

テストカバレッジに対する考え方の共通点

まず最初に、テストカバレッジについて会話する中で見えてきた両チームで共通する考え方について紹介をします。

考え方1. テストカバレッジを上げることを目標にしない

テストカバレッジを上げることがそのまま品質の向上に繋がるわけではありません。これは多くの開発チームが経験する課題であり、「単体テストの考え方/使い方」などの書籍でも指摘されています。

https://book.mynavi.jp/ec/products/detail/id=134252

カバレッジが低いことはテストコードの質が悪いことを判断するのに役立ちますが、カバレッジが高いことはそのままテストコードの質が高いことを示すわけではありません。そのため、Nstockの開発チームではカバレッジを指標として利用するにとどめ、カバレッジを上げることを目標とはしていません。

ある指標を目標にすることについては、弊社のエンジニアが登壇した開発生産性カンファレンス2025の基調講演でもケント・ベック氏が「指標が目標になるとそれは良い指標ではなくなる」と語っていたことが印象的でした。これはグッドハートの法則として知られています。

https://tech.findy.co.jp/entry/2025/10/20/070000

本講演の中では、PR(プルリクエスト)を例に指標を目標にすることの影響について話していました。優れたプログラマーは小さなPRを多く出す傾向があるからといってPR数を目標にしてしまう[1]と、過度にPRが細切れになり、逆に生産性が下がってしまうという内容です。テストカバレッジでも同じような事象が発生することは想像できます。

別の例として、先述の「単体テストの考え方/使い方」に出てくる病院での誤った目標設定例があります。ある病院が発熱している患者の体温を特定の体温に下げることを目標にする。そのために冷風などあらゆる手段で体温を下げようとしていたら、それはもちろん間違いで治療していることになりません。個人的にはこの例えも分かりやすいなと感じます。

では、カバレッジを上げることを目標とせずにどう扱うのが良いのか。Nstockでは先述の通り、テストコードの質の低下を防ぐ役割として利用しています。プロダクトごとに妥当な基準を設定し、カバレッジを上げてその基準を満たしたあとは、カバレッジの低下によってテストコードの質が下がっていないかをチェックするアラートとして活用しています。

考え方2. 妥当な基準を設定し維持する

次に、具体的にどの程度のテストカバレッジであれば、テストコードの質が悪いと判断しているか紹介します。Nstockの開発チームでは両チームとも偶然Googleの事例: Code Coverage Best Practicesを参考にしていました。Code Coverage Best Practicesでは、全てのプロダクトに一律で適用できるわけではないとしながらも、ガイドラインとして、60%以上を許容可能なラインとして提示していました。

Although there is no “ideal code coverage number,” at Google we offer the general guidelines of 60% as “acceptable”, 75% as “commendable” and 90% as “exemplary.”

Nstockの各チームでも、全体としてはまずは60%以上のカバレッジを基準とし、それ以上のカバレッジを維持できる状態を整えました。ただし、セカンダリーについては、重要なビジネスロジック部分についてはc1で75%以上を維持する基準としており、そのあたりの詳細な基準値については後述します。

カバレッジを100%にしなくてよいのでしょうか?そもそもカバレッジを100%にしたところで、すべてのバグを見つけることができないことは、「知識ゼロから学ぶソフトウェアテスト【改訂版】」[2]でも指摘されています。

https://www.shoeisha.co.jp/book/detail/9784798130606

本書籍では以下のようなバグはカバレッジでは見つけられない場合があると指摘されていました。

・プログラムのループに関するバグ
・要求仕様自体が間違っていたり、機能が備わっていないバグ
・データに関するバグ
・タイミングに関するバグ

また、この書籍の中では「一般の商用ソフトウェアならカバレッジは60~90%程度で十分」であると著者の考えが述べられています。

プロダクトの特性に応じた最適なカバレッジが存在するため、全てのプロダクトで同じ基準が当てはまるわけではありません。そのため、むやみに100%を目指すのではなく、投資対効果を考慮した現実的なカバレッジ基準を設定し維持することが重要であると、Nstockでは考えています。

プロダクトフェーズごとのアプローチ比較

一方で、こうしたカバレッジの考え方を実現するための具体的なアプローチには、各開発チームによって違いがありました。その違いは、既に本番稼働をしている既存プロダクトか、立ち上げ中の新規プロダクトなのか、プロダクトフェーズの違いに起因しているように感じます。

以下では、既存プロダクトである株式報酬SaaSと新規プロダクトであるセカンダリーの取り組みをそれぞれ紹介します。比較しやすいよう、同じセクション構成で説明していきます。

株式報酬SaaS:既存プロダクト

テストカバレッジへの取り組みの背景

株式報酬SaaSは、リリースから2年が経過し、本番環境で稼働している既存プロダクトです。開発当初からテストは書かれていたものの、DB接続を含むインテグレーションテストが中心でした。I/Oを伴うテストは実行が遅く、テストデータ(fixture)の準備が大変だったため、インテグレーションテストは正常系に絞り、I/Oを伴わないユニットテストを中心とする方針にシフトしていきました。

その中で、コードベース全体の品質を客観的に把握する指標がありませんでした。そこで、プロダクトの品質状態を把握するための一つの指標として、テストカバレッジを可視化することにしました。カバレッジを計測することで、現在地を明確にし、チーム全体で共通認識を持てるようにすることが目的でした。

計測と基準を満たすためのアプローチ

計測と可視化の仕組み

株式報酬SaaSでは、カバレッジ計測ツールとしてJaCoCoを利用しています。C0(命令網羅)とC1(分岐網羅)の両方が測れて、どのファイルのどの行がカバーされていないかをHTMLレポートで確認できるのが便利です。

チーム全体がカバレッジの推移を意識しやすくする工夫として、計測結果はGitHub Actionsで1日1回自動的に取得し、Slackに通知するようにしました。JaCoCoのXMLレポートをxmllintでパースして計算し、シンプルな形に整形してからSlackに通知しています。


1日1回Slackに通知されるカバレッジ

また、JaCoCoのレポートをGitHub Pagesにホスティングしておくことで、いつでも詳細を閲覧できるようにしています。


GitHub PagesにホスティングされているJaCoCoのレポート

改善の進め方と成果

取り組み開始時点では、C0が65.0%、C1が29.7% という状態でした。株式報酬SaaSは、お客様への価値に直結する開発の優先度が高い状況です。そのため、カバレッジ向上のための専用タスクを立てるのではなく、ボーイ/ガールスカウトルール(来た時よりも美しく)の精神で、日々の開発の中で少しずつ改善していくスタンスを取りました。

具体的には、機能追加やバグ修正で既存コードに触れるタイミングで、その周辺のテストも追加・改善していくというアプローチです。新たに機能実装する際も、その機能のテストだけでなく、関連する既存コードのテストが薄ければついでに補完していました。他にも、JavaのRecordクラスを利用してボイラープレートコードを減らしたり、デッドコードを削除してカバレッジの分母を減らしたりといった工夫もしています。

地道に取り組みを続けた結果、約1年間で、C0は65.0% → 81.6%に、C1は29.7% → 59.7% に向上しました。

取り組みから得られたこと

取り組みを進める中で、最も大きな成果は「会話のきっかけ」が生まれたことです。もちろん、副次的に品質にも寄与していると思いますが、チームでテストについて話す機会が自然に増えたと感じています。

Slackに通知が来て、カバレッジが下がっていると、「何が影響してるかな」「最近マージしたPRにテストが足りてなかったかも」と意識が向くようになります。もともとテストへの意識は高いチームでしたが、こうした気づきを通じて、意識がより具体的な行動につながりやすくなりました。

また、「このあたりのコードをリファクタリングするついでに、カバレッジも上げられないか」といった会話も生まれるようになりました。数字があることで、改善の機会を見つけやすくなったと感じています。

カバレッジはあくまで指標の一つに過ぎませんが、定量的に数値が見えることで具体的な会話ができるようになります。チームでテストについて話し合うための共通言語として、とても役立っています。

セカンダリー:新規プロダクト

テストカバレッジへの取り組みの背景

セカンダリーでは、開発が進む中で、ユニットテストやDB接続を含むインテグレーションテストは書いていました。一方、カバレッジは取っておらず、現在の状態がわかりづらくなっていました。

あるときチームのふりかえりの中で、今後さらに開発を進めたり、本番稼働を見越した際に、カバレッジを1つの指標として取得しておいた方が良さそうだという話題が出ました。また、システム監査の準備を進める中で、監査要件への対応としてテストカバレッジをさらに充実させる必要もありました。

計測と基準を満たすためのアプローチ

計測と可視化の仕組み

セカンダリーのバックエンドAPIは、オニオンアーキテクチャに基づいてGradleのマルチプロジェクトで構成されており、カバレッジもサブプロジェクト毎に計測をしています。具体的には、Presentation層 + UseCase層のアプリケーション用プロジェクト、Infrastructure層のプロジェクト、Domain層のプロジェクトごとに計測するといった具合です。

計測ツールにはKoverを使っており、全体とDomain層、UseCase層を抽出して監視しています。

基準としては、全体をC0で60%、Domain層とUseCase層はC1で75%以上と設定しました。Domain層とUseCase層の基準を上げている理由は、この2つの層にビジネス要件が集中しているためです。Domain層がドメインロジックの中心であることは言うまでもありませんが、UseCase層でも複数のドメイン概念がどのような順序や条件下で組み合わされるかといったビジネス要件が表現されているため、テストの重点箇所としました。

計測結果は各PRにコメントで出力されるので、開発者は自分の変更がカバレッジにどう影響したかをすぐに確認できます。


PRのComment上にカバレッジを出力している

なお、PRのコメントだけだと最新の数字が分かりづらいので、PRがマージされるたびにGitHub Issueに最新のカバレッジを記録し、現在の状態を把握しやすくもしています。

このようにCIの中にカバレッジを組み込むことで開発者が日常的にカバレッジを意識するようにしました。こちらは、先のケント・ベック氏の基調講演の中でも指標は、意識向上の促進として、ただ可視化すれば良いと触れられていたことにも通じます。

改善の進め方と成果

ちょうどカバレッジに取り組み始めた頃、Devinの活用に慣れてきたことやドキュメント整備が進んでいたことから、試験的にAIツールを使ってテストコード実装を試してみることにしました。結果として、質の高いテストコードを生成できることが確認できたため、本格的にAIを活用したアプローチで進めることを決めました。

AIツールの役割分担

このプロジェクトでは、複数のAIツールを適材適所で活用しました。対応当時(2025年1-3月頃)では、Devin単体での対応にまだ不安があったため、リスク低減のために複数のAIを組み合わせる戦略を採用しました。

Claude や ChatGPT は、テストコード生成ガイドラインの整備や、Devinへの指示プロンプトの作成を担当しました。Devinサーチ(Ask Devin: Devinの計画立案機能)では、全体のテスト計画を立て、各Devinセッションへの具体的な指示プロンプトを生成します。そして、複数のDevinセッションが並列でテストコードを実装しPRを作成するという役割分担です。

実装の進め方

まず準備フェーズとして、ClaudeやChatGPTでテストコードの要件を整理し、テストコード生成ガイドラインとしてリポジトリに配置しました。次に、レイヤーごとにお手本となるテストコードをパターン別に数ファイルずつ実装しました。このお手本コードは、AIが参照する記述スタイルやテストポイントの基準となるため、質を担保する上で重要な役割を果たしました。

実装フェーズでは、ガイドラインをベースにDevinサーチへの指示用プロンプトをClaudeやChatGPTで作成します。例えば、「ユースケース層のカバレッジを現状70%から75%以上に向上させる。業務上重要度の高い処理を優先し、既存のテストコードを参考にして4-5ファイルのテストを実装する」といった具体的な基準と方針を示します。

Devinサーチは、この指示を受けて、対象ファイルを分析し、各Devinセッション向けの詳細なプロンプトを生成します。生成されたプロンプトには、対象ファイルごとのテスト要件、正常系・異常系のテストケース、参考にすべき既存テストコードなどが含まれます。これらのプロンプトを4-5個のDevinセッションに分配し、並列で実装することで作業時間を大幅に短縮しました。重要なファイルについては、レビューに時間をかけられるよう、並列数を2-3に減らして調整しました。

PRのレビューでは、生成されたテストコードの質や網羅性を確認します。想定通りレビュー負荷は軽く抑えられましたが、PRのレビューで気づいた改善点をガイドラインに追記し、次回のプロンプトに反映させるという継続的な改善サイクルを回していました。

成果

この取り組みを1週間程度で実施した結果、設定していた基準(Overall 60%以上、Domain層・Usecase層 75%以上)をすべて満たすことができました。作業自体は1人のエンジニアが他のタスクと並行して進めましたが、従来通りの開発フローで実装した場合の想定期間が1ヶ月程度だったことを考えると大幅な時間短縮とコスト削減を実現できました。

取り組みから得られたこと

CIに組み込むことで、日常的に基準となるカバレッジを意識するようになりました。仮に基準が大きく下がるような変更を加えている場合には、テストコードが足りてないことをすぐに把握し、対応できるようになっています。

また、この取り組みを通じて、AIにテストコードを生成させるためのドキュメント整備やプロンプト設計のノウハウが蓄積され、今後の同様のタスクにも応用できる資産となりました。

まとめ

フェーズごとのアプローチの有効性

2つのプロダクトは開発フェーズが異なるため、それぞれに適したアプローチを取りました。

既存プロダクトである株式報酬SaaSでは、「ボーイ/ガールスカウトルール」のような段階的アプローチが機能しました。本番運用中は優先度の高い機能追加やバグ修正が日々発生するため、それらに紐付ける形でテストを充実させるのが現実的でした。また、カバレッジの意識化には、Slack上での会話やGitHub Pagesでの可視化を活用しました。この取り組みを通じて、チーム内でカバレッジへの意識が定着し、指標をもとにした会話ができるようになりました。

一方、セカンダリーでは、新規プロダクトという特性を活かし、初期段階での基準の確保を重視しました。AI活用により重要なビジネスロジックを重点的にカバーするアプローチを取り、CIでの自動取得により初期段階から自然と指標を意識することができるようになりました。

今後の展開と学び

Nstockではこれからも複数のプロダクトを立ち上げていく予定です。今回ブログとしてまとめることでカバレッジへの取り組みが整理できたので、他のプロダクトにも応用していけたらと考えています。

重要なのは、カバレッジを「指標の一つ」として捉えてプロダクトの状態を把握し、チーム内に圧力をかけるのではなく、改善への動機を生み出すためのツールとして活用することです。

100%を目指すのではなく、ビジネス価値を守るための投資として、現実的で持続可能なテスト戦略を模索していく。その過程で、カバレッジの取得・向上は手段であって目的ではないという原点を見失わないことが、長期的なプロダクト品質の向上につながると考えています。

各組織のプロダクトフェーズや開発体制は異なりますが、本記事で紹介したアプローチが、みなさんの組織に適したテスト戦略を考える際の参考になれば幸いです。

脚注
  1. 厳密には、登壇の中ではPR数のランキング表を作ることを例にしていました。 ↩︎

  2. 23年11月に第3版が発売されたようですが、筆者は改訂版しか読んだことがないため、そちらを引用しています。 ↩︎

Nstock Tech Blog

Discussion