🎸

なぜユニットテストはC1カバレッジで80%くらいあるといいのだろう?〜とある開発会社の事例〜

2024/04/15に公開

はじめに

DevOpsとマイクロサービス時代のQA: 高品質なソフトウェアを目指してと題した記事を公開しました。この記事を振り返りつつ、品質が高いとされる状態とは具体的に何か、自らに問い直してみると、まず思い浮かぶのが「ユニットテストでC1カバレッジ80%以上」という点です。

しかし、なぜユニットテストはC1カバレッジで80%程度あると良いのでしょうか。過去の経験を書き出したいと思います。

https://youtu.be/am386qAljcw

ケーススタディ

背景

フリーランスから正社員への転職を経て、開発会社に入社しました。バグゼロでのリリース経験を活かし、品質を高めるため品質保証部の立ち上げを目指す会社を選びました。(フリーランスから正社員への転職理由については、興味があれば詳しく述べます)目標は、開発プロセスの標準化を通じた高品質な製品の実現です。

品質保証部の立ち上げに伴い、多岐にわたる取り組みを実施しました。プロセスの改善、標準化の推進、作業の可視化、そしてユニットテストの普及といった活動を通じて、組織全体の品質向上に努めました。ここでは、これらの取り組みによって得られた成果に焦点を当てて説明します。

ユニットテスト導入の成功事例 vs. 導入しなかった事例の教訓

ユニットテストを導入したプロジェクト

3〜4人のエンジニアで約6ヶ月かけて開発したプロジェクトについて記述します。このプロジェクトは、所属していた会社が顧客から受託したもので、さらにパートナー企業に外注していました。契約上の制約、例えばユニットテストが見積もりに含まれていないことなど、いくつかの障壁がありましたが、テスト仕様書の作成や受け入れテスト範囲の拡大など、交渉を重ねてユニットテストの導入を実現しました。

開発プロセスに直接コードを書かずに関わるのはこれが初めてで、最初は戸惑いもありましたが、開発会社に出向いてソースコードのレビューや質問への回答などを行いました。プロジェクト中盤には、開発者たちがユニットテストに熱中しすぎてコードカバレッジが90%近くに達し、書きすぎにブレーキをかける状況に至りました。
(うれしい悲鳴でした)

プロジェクトに関わる残業の有無について尋ねたところ、他のプロジェクトと比較して残業は少なく、心身への負担も軽減されたとのことでした。ブラックボックステスト実施によりバグが発見されましたが、予想以上に少なく、バグ修正時のデグレードもなかったため、開発者は安心してプルリクエストを出せるようになったと喜んでいました。

最終的に納期を守り、成功と評価されるプロジェクトになりました。

参考

ユニットテストを導入しなかったプロダクト

こちらも3人から4人のエンジニアで結果的に1年以上かけて開発したプロダクトです。ユニットテストを導入したプロジェクトと同様に、所属していた会社が顧客から請け負い、さらにパートナー企業に外注していました。こちらのプロジェクトでは、契約上の理由を盾にユニットテスト導入が拒否され、開発が進められました。

エンジニアのスキルセットやマインドセットなど、様々な問題がある中で、テスト段階で多くのバグが発見されました。バグを指摘し修正しても、デグレーション(機能退行)が頻繁に起こりました。顧客からの仕様変更が多かったことも影響しましたが、納品時には多数のバグが残る状態でした。

その後、バグと低品質に関するクレームが相次ぎ、文字通りの炎上プロジェクトとなりました。最終的には顧客の信頼を失い、そのプロダクトの契約解除に至りました。

考察 ユニットテストを導入しなかったプロダクトが炎上したのは?

ユニットテストを導入したプロジェクトは、以前に述べた「なぜユニットテストはC1カバレッジで80%くらいあると良いのか?〜あるプロダクトの事例から〜」で挙げた理由と大きく変わりません。したがって、ここではプロジェクトが炎上した原因を詳しく掘り下げてみます。

ユニットテスト以外の要因は?

元々、開発者のスキルや要件定義から実装への落とし込みの不十分さなど、ユニットテスト以前の問題が多く存在していました。そのため、ユニットテストが不在であることがプロジェクトの炎上を直接的な原因とするには、必ずしも明確な理由とは言えないかもしれません。

インテグレーションテストでのバグ多発

ユニットテストを強く支持する立場から、この点には触れざるを得ません。自社でテストを作成し実行しました。基本的な同値分割と境界値分析を用いたテスト設計に基づき、テストを行いました。テストを開始すると、バグが多数見つかりました。開発者にフィードバックしても、修正が新たなバグを生むか、既存のバグを再発させることが頻繁にありました。

もしユニットテストがあったら

  • ユニットテストの実装時や実行時にバグを検出し修正することで、インテグレーションテスト時に発見される可能性のあるバグを初期段階で防ぐことができます。
  • ユニットテストを書く過程では、クラスの設計を適切に行い、結果的にメソッドを細分化する必要があります。このようにすると、一つのメソッドに一つの機能が割り当てられ、その責務が明確になります。ユニットテストがこのメソッド単位の責務を常時検証することにより、仮にデグレードが発生してもそれを迅速に検知することが可能になります。
  • 同値分割および境界値分析を用いて作成したインテグレーションテストのテスト仕様をレビューした際、多くの部分がユニットテストによって既にカバーされていることがわかりました。このことから、インテグレーションテストでカバーすべきテストの範囲がユニットテストによって一部代行されることがあります。ユニットテストとインテグレーションテストの関連付けを試みましたが、そのボリュームの多さと時間的な制約から、全てを実行することはできませんでした。

今後

書けるか自信ありませんが…次のことも言及が必要かなと考えています。

  • ユーザー体験への影響
  • 継続的インテグレーション(CI)との関連
  • 長期的なメンテナンスの観点

Discussion