はじめに
社員の皆さんはこんな奴が最近エンジニアになって頑張ってるんだなと暖かい目で読んでいただければと思います。
社外の方やエンジニアを目指している方は少しでも学習の参考や、コネクター・ジャパンに興味を持っていただければと思います。
さて初めに、皆さんは単体テストについてどれだけ知っていますか?
単体テストはソフトウェア開発の重要な部分であり、品質を維持し、持続可能な開発を可能にするためのキーとなります。この記事では、「Manning Publishing: Unit Testing Principles, Practices, and Patterns」の翻訳書である「単体テストの考え方/使い方」という本を読んで「単体テスト」に着目して学んだことを記事にしました。
単体テストの重要性、その構造、そして良いテストを作成するための方法について深く掘り下げます。
自己紹介
未経験から独学でプログラミング学習し5ヶ月でLaravelでポートフォリオを作成しました。そして現在は自社開発企業に入社し、WEBエンジニアとしてプロダクト開発に携わっています。エンジニアになって早いもので4ヶ月経ちました。
この記事を書いた理由
この本から得た知識をアウトプットしたいと思いました。また、単体テストに関する理解を深めることで、開発プロジェクトの成長を促進させることを目指しています。
記事の流れ
- 単体テストとは何か
- 単体テストの重要性
- 単体テストの3つの手法
- じゃあどの単体テストを優先するべきか
1. 単体テストとは何か
単体テストは、小さなコード片(「単体」と呼ばれる)の振る舞いを検証するテストで、実行時間が短く、隔離された状態で実行されます。これにより、個々のコンポーネントが仕様通りに機能していることを確認することができます。
なぜ単体テストを行うのか?
単体テストの目標は、
「ソフトウェア開発プロジェクトの成長を持続可能なものにすること」
です。
逆に考えると、テストコードを書かないプロジェクトは持続出来ずいずれ修復不可能な状況になりかねないとも言えます。実際にこの書籍では、立ち上げ時期はコード数が少ないためテストコードを書く恩恵が少ないが、コードの量が増えると複雑化していくので、テストコードを書かなければプロジェクトの持続は不可能とされています。
それだけ重要です。
ソフトウェアテストの目的や対象ごとに複数のテストケースを良質にまとめたものにより、プロダクションコードに変更を加えた際に退行が発生しないことを保証し、機能追加やリファクタリングを容易にします。
2. 良い単体テストを構成する4つの柱
良い単体テストは、以下の4つの重要な要素で構成されます。これらはテストの価値を決定する際に重要な役割を果たします。
退行に対する保護
これはテストがどれだけ効果的にバグを検出できるかを示します。実行されるプロダクションコードが多ければ多いほど、発見されるバグの数も増えます。特にビジネス上重要な機能の場合、バグが大きな影響を及ぼすため、コードの複雑さやドメインの重要性を考慮することが必須です。
リファクタリングへの耐性
これは偽陽性を出さずにどれだけリファクタリングが可能かを示す指標です。偽陽性は誤った警告を意味し、テスト対象のコードが実際には正しく機能しているにもかかわらず、テストが失敗する状況を指します。これにより、テストの信頼性が低下し、本番環境に問題があるコードが導入されたり、リファクタリングが避けられるようになります。重要なのは、テストの検証内容が実装の詳細ではなく、最終的な結果に焦点を当てることです。
迅速なフィードバック
これはテストの実行時間がどれだけ短いかに関連します。テストが迅速に実行されるほど、より多くのテストケースを頻繁に実施できるようになり、結果的にバグの検出が早まり、バグ修正のコストが削減されます。
保守のしやすさ
テストケースの理解と実行の難易度を示します。テストケースが分かりやすく、実行が容易であれば、保守性は向上します。
これらの要素を完全に実現することは難しいです。そのため、「リファクタリングへの耐性」と「保守のしやすさ」に最大限取り組むことが重要であり、残りの要素はプロジェクトの全体バランスを考慮して管理する必要があります。
3. 単体テストの3つの手法
単体テストには、主に以下の3つの手法があります。
-
出力値ベーステスト
この手法は、プログラムが返す結果だけをチェックします。ここでは、テスト対象のコードが副作用を生じさせず、単に呼び出し元に戻り値を返すだけという前提があります。 -
状態ベーステスト
処理後のプログラムの状態をチェックします。これは、システムやデータベースなど、プログラムの外部状態も含めて検証します。 -
コミュニケーションベーステスト
モック(仮のオブジェクト)を使って、プログラムの部品間のやり取りを検証します。
出力値ベーステストは、簡単なコードに最適で、リファクタリング(コードの改善)に強いです。また、小さくて簡潔なテストケースになるため、保守もしやすくなります。しかし、この手法はすべてのテストには向いてません。すべてのテストケースをこの手法で実施する必要はないが、可能な限り多くのテストケースをこの手法で行うことが望ましいとされています。
4. じゃあどの単体テストを優先するべきか
単体テストを行う価値が最も高いコードは、「複雑なコード」もしくは「ドメインにおける重要性が高いコード」になります。なぜなら、そのようなコードをテストすることで、退行に対する保護が備わるようになるからです。DDD(ドメイン駆動設計)のような開発手法であれば役割に対する分割がしやすいので、テストがしやすい開発手法と言われています。
まとめ
この本は単体テストの重要性がこれでもかというほど教えてくれる本でした。
テストをする目的、何を優先してテストするべき、どうテストするべきかということを体系的に学ぶことができた。
C#ですが、サンプルコードがあって実際にリファクタリングしながらの説明や図がたくさん乗っていて全体的に読みやすい本でした。プロジェクトの成長を持続可能に出来るように、実践で実行していきます。
一緒に働く仲間を募集しています!
株式会社コネクター・ジャパンでは一緒に働いてくれる仲間を募集しています!
事業拡大に伴い、エンジニアさんを大募集しています。
興味のある方は下記リンクから弊社のことをぜひ知っていただき応募してもらえると嬉しいです。
▼会社について
https://www.wantedly.com/companies/cnctor/about
▼代表メッセージ
https://cnctor.jp/10years-anniversary/
▼応募はこちら
https://www.wantedly.com/projects/1522201
「ご質問があれば、Xまで気軽にDMをお送りください!」