’23年度入社の紙屋です!
本年度は単体テストに対して理解を深め、成果物のクオリティを担保するという点を目標の一つとして業務に取り組んでまいりました。
リリース前にテストを行い、早期に不具合を発見することもできましたが、テスト内容の不十分さや検証環境へリリース後、お客様からのご指摘で不具合を発見するなどの反省点もありました。
テストを行うための心構えとして備忘録的にまとめようと思います!
テストの目的と重要性
- バグの早期発見と修正が可能
- プログラマーの心理的安全性を保つ
- 機能改修時の予期せぬエラーを防ぐ
- コードの挙動理解を助ける
テストの考え方
- FeatureとUnitに分けて管理することが多い
* Feature(機能)テスト:
ユーザー目線のテストです。
より大きい範囲で行い、アプリケーションに求められる機能を確認します。
* Unit(単体)テスト:
プログラマ目線のテストです。
より小さい範囲で行い、各パーツごとにエラーがないかを確認します。 - ブラックボックステスト、ホワイトボックステストの目的を意識する
* ブラックボックステスト:
システムの外部から機能や仕様を検証します。
システムが仕様通りに動作するか、画面レイアウトや使いやすさを評価することに重点を置きます。
* ホワイトボックステスト:
内部のコード構造や処理フローを検証します。
内部ロジックのの正確性を評価します。
テストの作成
テストの作成から実行方法までLaravelを使用した方法でまとめようと思います。
- テスト作成のコマンド:
1php artisan make:test XxxxTest
上記コマンドはFeatureテストとして作成されます。
もしもUnitテストとして作る際は、オプションを付けましょう。
1php artisan make:test XxxxTest --unit
* ファイル名は通常 ‘XxxxTest.php’ の形式を指定します。
テストケース名には必ず「test」と入れ、「test***」とテスト名と条件なども記載します。
テストコードの構造
テストコードは以下のような形をとります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class ExampleTest extends TestCase { protected function setUp(): void { // テスト前の準備 parent::setUp(); } protected function tearDown(): void { // テスト後のクリーンアップ parent::tearDown(); } public function testExample() { // テストケース $this->assertTrue(true); } } |
setUp や tearDown はテストケースの事前・事後処理を行います。
* setUp:事前処理(変数の初期化やデータの準備など)
* tearDown:事後処理(不要なデータの削除など)
* setUpやtearDownを書く際は、メソッドの戻りと指定 ‘: void’ も忘れずに書くことが必要です。
アサーションについて
プログラミングのデバッグやテストのために用いられる方法の1つです。
以下のような働きをします。
- テスト結果を即座に確認できる
- テストが意図した通りに動作したかを検証できる
- テスト条件が妥当なデータかを判断できる
- テストが失敗した要因を特定しやすい
アサーションメソッドは主に以下のようなものがあります。
- assertTrue:実測値がtrueであることを期待
- assertFalse:実測値がfalseであることを期待
- assertEquals:実測値と予測値が一致することを期待
- assertSame:実測値と予測値が型も含めて一致することを期待
- assertEmpty:中身が空であることを期待
- assertNotEmpty:中身が空でないことを期待
- assetStatus:アクセス結果のステータスコードを確認
- assertRedirest:アクセス後、どこにリダイレクトされるかを確認
- assertSee:レスポンス内に特定の文字列が存在することを確認
テストの実行方法
- 全てのテストを実行する場合
1php artisan test - フォルダを指定してテストを実行する場合(例:フォルダ名tests/Feature)
1php artisan test tests/Feature - ファイルを指定してテストを実行する場合(例:ファイル名ExampleTest.php)
1php artisan test tests/Feature/ExampleTest.php - メソッド名を指定してテストを実行する場合(例:メソッド名testExample)
1php artisan test --filter testExample tests/Feature/ExampleTest.php
テストコード作成のポイント
- テストメソッドは簡潔に保つ
呼ばれるアサーションを条件分岐してしまうと、一貫したテスト結果が得られなくなる可能性があります。結果が数パターンある場合は、愚直にそのパターン数分テストを準備する必要があります。 - 必ず通るテストを書く(時間依存や確率的要素を避ける)
- ダミーデータは実際の内容に近い内容にする
データはより正確な方が本番環境に近い挙動のテストを行うことができます。 - テスト対象となるロジックはシンプルにする
複雑な条件になりそうな場合はメソッド化して対応します。そのほうがテストケースも少なくて済むことがあります。
ロジックはネスト構造を複数持たないよう心掛け、アーリーリターンを設けるなど対応します。 - 3つのAを意識する
〇 Arrange(準備):テストを行うにあたっての必要な準備段階のこと
〇 Act(実行):準備したデータを元にアクションを起こすこと
〇 Assert(検証):アクション後に期待する結果になっているか検証すること
上記3つのAを意識してテストを行います。
以上がテストについての基本になります。
単体テストを適切に実施することで、コードの品質向上とメンテナンス性の改善につながります。
なかなか時間が十分にとれず、また、多数存在する条件の洗い出しもできないとシステムの品質を担保することは難しいです。
先日参加したPHPカンファレンスでもテストの重要性に触れ、テストを書く習慣をつけ、継続して改善、向上していくように意識するようになりました。
開発に時間がかかりがちですが、テストの時間も十分に設け、自分へのフィードバックも兼ねて今後も取り組んでいきたいと思います。
日々の取り組みを重ね、また理解が進んだ段階でアウトプットできればと思います!