アプリケーション開発におけるテストの概要や概念 〜第１話〜

こんにちは、佐藤です。

アプリケーション開発においてテストが重要であると感じさせるきっかけが何回か起こり、テストについての考えを整理したいなと感じましたので、アプリケーション開発におけるテストについて紹介していきたいと思います。

[adinserter block="1"]

まず今回はテストに関する概要や概念について紹介した後、次回以降では具体的なテストコードを使いつつ、テストフレームワークも踏まえて紹介していきたいと思います。

アプリケーション開発におけるテストコードの重要性

アプリケーション開発において、実装したコードが意図通りの動作をするのかテストコードを使って実施することは重要です。

例えば、開発者が自ら実装したコードに関して人手で試しに操作し、うまく動くかどうかを確認する体制であったとしましょう。この場合、その確認が不十分である場合や、確認した時には問題なくても、後に行った他の実装が当時問題なかった動作に影響して問題が発生した場合に気が付くことができません。

また、意図しない動作が発見された際に、どのコードが原因となっているのかを知るために多くのコードを確認する必要が出てくるかもしれません。

人手で確認した場合でも、確認する内容が網羅されていれば、直近の変更が原因である可能性が高いと分かりますが、そうでなかった場合はどこまでが正常に動作しているのかを再び手動で確認するのは大変です。

テストコードが作成されていれば定期的にテストコードを実行することが出来るため、アプリケーションが意図した動作を行うか定期的に知ることが出来ます。そしてテストにより意図した動作を行うことが分かっているアプリケーションに対して機能追加や、リファクタリングをする場合にも、テストが成功すれば安心できます。

また、副次的に期待出来ることとして、テストコードがあれば、そのテスト結果が正しくなるようなアプリケーションを作った時点で実装が明確に終了と言えるというメリットや、テストコードが作成しやすくすることで、アプリケーションの部品単位や、振る舞い、責任範囲を意識することに繋がり、結果的に綺麗な責任範囲毎に分離することにつながることが期待できます。

このように、アプリケーション開発においてテストコードを作成することにより、テストコードによる実行結果という明確な理由を以って、アプリケーションの動作正当性を担保することが出来ます。

[adinserter block="1"]

テストとコードどちらを先に記述するか

テストコードを先に記述した方がよいとする意見があります。
テストファーストと呼ばれる手法です。

また、テストの内容を考えてからコードを記述するテスト駆動開発(Test driven development)や、そこから派生した振る舞い駆動開発(Behavior driven development)があります。

テストをいつ記述すべきかに関しては、様々な駆動開発手法があるということを理解した上で、各現場で適したものを採用できるようになるのが良いと思いますので、今回はどちらを先に記述すべきかは述べません。

[adinserter block="1"]

テスト駆動開発

テスト駆動開発とはアプリケーションに対するテストの内容を先行して考え、そのテストが成功する最小限のコードを実装する開発方式です。最小限のコードが記述出来たら、次にテスト内容を拡張させ、再びそのテストが成功するための実装を行い、これを繰り返します。(途中や最後には、冗長化された箇所をリファクタリングすることも含みます)

先行してテストの内容を考える方式であるため、テストファーストになることがほとんどだと思います。

メリットとしては、テストの内容があらかじめ決まるため、アプリケーション開発のゴールはテストが成功することであると判断することができます。

また、テストが困難になる事態がコード実装前・又は途中で分かります。テストが困難になる場合は、コードが密結合になりうる(又はなっている)事態と捉えられるため、設計を振り返る機会となります。その結果、密結合となる状態が回避され、責任範囲が綺麗に分離されたコードになることが期待できるというメリットがあります。

また、アプリケーションに対するテストが共に作成されるため、修正によるデグレが発生した場合にテストが失敗することが期待できるため、修正が必要な個所がすぐに調べることが出来るようになります。

[adinserter block="1"]

振る舞い駆動開発

振る舞い駆動開発とは、アプリケーションが振る舞うべき動作に着目し、その振る舞いをテスト項目として記述する開発手法です。

アプリケーションが振る舞うべき動作は要求仕様と同様です。

テストが正しくアプリケーションの振る舞いを記述することができていれば、アプリケーションが仕様に則っていることを示すことができます。

そのため、アプリケーションをリファクタリングしたい場合等、大幅な変更が加えられた場合にもテストが成功していれば、アプリケーションの振る舞いが変わっていないことが保証できます。

[adinserter block="1"]

テストファーストという手法について

テストファーストとはテストを先行して実施する手法です。

テストを先行して記述することで、アプリケーションに対して必ずテストが残るというメリットと、テストを作成した時点ではコードが存在しないため、テストが失敗するケースが必ず確認することが出来るというメリットがあります。

しかし、テスト自体もコードであることから、アプリケーションと同様に記述する工数がかかる点や、一度実装すれば終わりではなくアプリケーションの改修や仕様変更に追従して追加・修正し続けなくてはならないと言った側面があります。

特にユーザが操作する画面に関しては変更されることが多く、またテスト環境で JavaScript が動作できるようブラウザドライバを用意する等、環境整備にも工数がかかることも考えられ、更にそのドライバが修正された場合にも追従する必要がある等、多くの工数がかかるためテストコードは出来る限り最小限にしたいところです。

このように、テストを必ず先に作成するテストファーストが必ずしも得策とならない場合は存在するため、テストファーストはあくまで手法であると考え、現場に適した開発方式を採用するのが良いと言えるでしょう。

[adinserter block="1"]

何をテストするのか

テストする対象に関して、開発者がアプリケーションをどれだけの単位でテストを行うのかの違いで、ユニットテスト、インテグレーションテストがあります。

また、少し観点が異なりますがなるべく本番に近い状態でシステム全体をテストするシステムテストがあります。

それぞれのテストの違いについて説明していきます。

[adinserter block="1"]

ユニットテスト

ユニットテストはアプリケーションを構成するコードの最小単位に対して行うテストです。
関数・メソッドに対するテストがこれにあたります。

正しい動作をした場合のコードパス以外にも、意図しないケースでのコードパスに対して、エラーハンドリングが行われているかどうか等を調べます。

1つ1つのパーツとしての動作をテストすることが目的であるため、それらが連携した場合の動作はインテグレーションテストとして記述することになります。

[adinserter block="1"]

インテグレーションテスト

インテグレーションテストとはアプリケーションを構成するパーツが連携できているか確認するテストです。
アプリケーション内モジュールの連携、他システムとの連携が行えていることを確認するテストです。

[adinserter block="1"]

システムテスト

システムテストはなるべく本番に近い環境において多角的なケースに対して行うテストです。

アプリケーションが動作するハードウェア環境や利用するデータもなるべく本番に近いものを利用することが望まれます。

[adinserter block="1"]

どのような観点でテストするのか

テストを行う際、調べる観点によっても違いがあります。

ここでは、ブラックボックステスト、グレーボックステスト、ホワイトボックステストについてそれぞれ述べます。

[adinserter block="1"]

ブラックボックステスト

ブラックボックステストとは、アプリケーション開発の依頼者と同様に、ユースケースに従って INPUT と OUTPUT のみを見るテストです。アプリケーション内部の動作やデータは一切見ることはありません。

入力したデータに対して期待した結果が返ってくることの検証や、何か値をユーザが入力する場合に受け付けて欲しくないデータ(金額が0.5円の入金や、誕生日が0やマイナス等)を使っても問題が無いか等も検証します。

[adinserter block="1"]

グレーボックステスト

グレーボックステストはテスターと同様に、基本的にユースケースに従って INPUT と OUTPUT を確認するが、その操作によってデータが適切に変更されているかどうかを少しだけ確認するテストです。

残るべき監査記録が存在することや正しいロギングが行われているかどうか、またはデータが別システムへ転送されているかどうかを調べます。

ユーザが調べることができない領域に監査記録が残る仕様である場合、アプリケーションの操作を行った場合に正しく監査記録が残っているかどうかを DB のデータを直接調べるか、専用のツールを使うなどして検証します。

[adinserter block="1"]

ホワイトボックステスト

ホワイトボックステストは、開発者と同様に、すべての情報を確認するテストです。

コードのさまざまな分岐を全て通って意図通りであるか、適切なエラー処理が行われているか、仕様通りの動作であるか、リソース制約への適切な対処が行われているか等を調べます。

例えば、メソッドがスレッドセーフであることが要求されている場合に、複数のスレッドからメソッドを実行しても意図した動作をするかどうかなどを検証します。

[adinserter block="1"]

まとめ

今回、アプリケーション開発においてテストが重要であること、テストを先に記述する方式が存在すること、テストする対象や観点による違いがあることなどを紹介しました。

次回は、テストコードを紹介しながら、テストを分かりやすく記述するための考え方や、テストフレームワークについて紹介したいと思います。

佐藤

Profile:最後の砦を守る番人。すべてを受け止め、すべてを跳ね返す超人。