不具合に対するテストの書き方
本文は、以下の書籍を参考にしました。
継続的インテグレーション入門 開発プロセスを自動化する47の作法
- 作者: ポール・M・デュバル,スティーブ・M・マティアス,アンドリュー・グローバー,大塚庸史,丸山大輔,岡本裕二,亀村圭助
- 出版社/メーカー: 日経BP社
- 発売日: 2009/08/06
- メディア: 単行本(ソフトカバー)
- 購入: 13人 クリック: 345回
- この商品を含むブログ (35件) を見る
想定外のアプリケーションの動きによって不具合が見つかった場合、
その対応として第一歩として、この不具合を明らかにするためのテストケースを書きます。
例えば、下記のようなメソッドを実装して実行してみると、
public int findWord(String str){
int value = databese.get(str);
return value;
}
例外が発生してしまうという不具合が発生しました。
現象としてはFindException(データベースから文字列strに一致するものが見つけられません。。。)
が発生しているようです。
この対応のために、この不具合を再現するテストコードを書きます。
public void testFindWord(){
String str = "test";
try{
int value = databese.get(str);
} catch (FindException e) {
TestCase.fail("Don't find word" + str); //例外が発生したらテスト失敗
}
}
この時点ではこのテストコードを実行すると、もちろん例外が発生しテスト失敗になります。
この後、例外が発生しないようにfindWordを修正し、テストが成功するまで修正を繰り返します。
今回のケースでは、databaseのサイズが0の場合が十分に想定されていなかったようです。
今回はとりあえず0を返すようにしておきます。
public int findWord(String str){
if (database.size() == 0) {
return 0;
}
int value = databese.get(str);
return value;
}
これでテストを実行してみると見事にテスト成功しました。
修正完了!めでたし、めでたし。。。。。
。。。。。と、多くの開発者は行動すると思います。
この手法は、「欠陥駆動開発」といわれる手法で広く行われています。
しかし、この手法には以下の問題点があります。
- このテストコードは単に例外を発生しないことを確かめているにすぎない。。。
- 修正した後の振る舞い(今回の例ではdatabaseのサイズが0の場合に0を返すという仕様)を確かめていません。。。
Aさん「じゃあ、最初からテストコードで0を返すことを確かめりゃいいじゃん!」
Bさん「けど、最初はどこに不具合があって、どう修正するかわかんないのに、そんなテストコード書けなくない?」
Aさん「確かに(´・ω・`)。。。。。」
ってな、感じになります。
以下からが、開発者は行うべき行動です。
-----------------------------------------------------
- 例外が発生したらテストが「成功」となるテストコードを書く。
- そのテストコードを失敗するようにコードを修正する。(=例外が発生しなくなる)
- 修正した新しい振る舞いを確認するために、テストコードを修正する。
- テスト実行->成功。めでたし、めでたし
具体的なコードは以下の通り、
1.
public void testFindWord(){
String str = "test";
try{
int value = databese.get(str);
TestCase.fail("This should throw an Exception"); // 例外が発生しなかったらテスト失敗
} catch (FindException e) {
TestCase.assertTrue(e + "OK"); //例外が発生したらテスト成功
}
}
このテストコードを実行すると例外が発生しますが、
テストとしては成功です。これで不具合を再現したことになります。
次にコードの修正です。これは前と同じです。
2.
public int findWord(String str){
if (database.size() == 0) {
return 0;
}
int value = databese.get(str);
return value;
}
この修正により例外が発生しなくなり、テストは失敗になります。
次に、修正した新しい振る舞い(0を返す仕様のこと)を確認するために、
テストコードを修正します。
3.
public void testFindWord(){
String str = "test";
try{
int value = databese.get(str);
TestCase.assertNull("should have received back 0", value == 0); // 0ならOK
} catch (FindException e) {
TestCase.fali("This shoud not throw an exception"); //例外が発生したらテスト失敗
}
}
4.テスト実行すると、成功となります。
このアプローチは、従来の「欠陥駆動開発」と同様に
- 不具合の修正
- 不具合の再発の防止(テストコードの資産化)
に加え、
- 不具合の修正による新しい振る舞いの検証
を行うことできます。