Chapter 07

テストの種類とそれぞれの目的

nobuhito
nobuhito
2022.03.06に更新

テストと言ってもプログラム作成時には様々なテストがあります。
テストの種類は大きく分けて「単体テスト」「結合テスト」「システムテスト」「ユーザーテスト」の 4 つがあり、順に規模が大きくなり内容も複雑になり時間がかかるようになっていきます。

https://www.qbook.jp/column/20190703_616.html

どのレベルまでやるかについては規模や重要度合いによって変わってきますが、最低でもユーザーテストは必要ですし、出来れば単体テストもしておくとレビューが早くなります。

単体テスト

よくユニットテストと呼ばれるものです。これは「スパゲッティコードとならないために」で分割した関数だったり、作成したクラスについてのテストです。自分が書いたコードを、自分で間違ってないことを確認するためのテストとなります。

たとえば以下のような関数があったとしましょう。

function sum() {
  return a + b;
}

以下のテストを実行してエラーにならなければ、結果が正しいことを確実に証明できます。

testSum();
function testSum() {
  console.assert(sum(1, 1) === 2);
  console.assert(sum(1,1) === 0);
}

簡単な関数なのでバグが発生する可能性は非常に低く見えますが、このテストは実行するとエラーになります。
なぜなら、仕様的には文字列を与えた場合でも数字の 0 を返して欲しいから。

このように、文字列を与えた場合に「結合させるの」か「0 を返すべき」か、それとも「エラーにする」のかはきちんと決めておく必要があります。

もしテストが書かれていれば、文字列を与えた場合は 0 になることを期待している関数なのだなということがひと目で分かります。
仕様書で細かく表現してもよいですが、テストを書いておけば仕様も分かる上、実装上問題ないかもすぐ分かります。コードがドキュメントになるわけです。

単体テストは理想を言えば関数全てに対して書かれていることが理想ですが、それはそれでなかなか難しいのでクリティカルなところを中心に地道に揃えていくしかありません。
また、関数の処理結果が同じになることを担保しながら内部処理を変える場合は、単体テストを書いてから内部処理を書き換えると心理的にも安心できます。

仕組み的には自動化もしくは簡単に実行できるようしておき、定期的にエラーが発生しないか確認すると良いでしょう。

また、単体テストを考える場合は「依存性の注入」ということを意識しながら、テストしやすい関数やクラスを作成することもポイントとなります(実際はもっと高度な考えなのでさわりと言うか考え方です)。
どこかにデータを保存する関数があったとしても、関数内で保存するファイル名を指定しないようにし、引数で渡すようにします。たとえばデータをファイルサーバーのどこかに保存する場合などです。
依存性の注入を意識することでファイルサーバーがない環境でもテストすることが出来るようなり、テストの自動化が可能となります。

https://ja.wikipedia.org/wiki/依存性の注入

結合テスト

結合テストは、テスト済みの関数やクラスを組み合わせて使った場合に「意図しない問題が発生しないか」というテストです。
先の単体テストの例でいうと、確実に数字を戻す仕様となっている関数に対して、プログラムの作り的には null を返してもらいたい場合など、組合せて使う場合にチェックするテストです。

テスト項目としては「詳細仕様書」に沿った内容を確認するので、データベースのドライバやテーブル構造などについての確認テストもこれに含まれます。

システムテスト

システムテストはユーザーテスト前に実行する全体のテストです。「ユーザーと意識合わせした内容が確実に実装されているか」がポイントで、作成者側が主体となって「外部仕様書」で決めた内容がクリアされているかを確認します。

ユーザーテスト

ユーザーテストはユーザー側の受け入れテストです。使い心地なども含めて「外部仕様書」で決めた内容がクリアされているかを確認します。

もし「外部仕様書」がしっかりしてない場合は、ここで双方の意見が合わずに面倒なこととなってしまうケースが多いです。
ユーザーテストまで行ったプログラムを、なかったことにすることは難しいです。殆どの場合はユーザー側の要望が通りますので、結局は大きく作り直すことになる場合も多いです。