SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Javaの単体テストでランダムなデータを活用する

QaRandomizerを利用し、ランダムデータを用いた単体テストを実行

単体テストでありがちな落とし穴

 では、ランダムデータを利用した単体テストの話に進んでいきましょう。テスト駆動開発(TDD:test-driven development)の基本原則の1つに、「コードより先にテストを作成する」というものがあります。そこで、まずはAddressオブジェクトから考えてみましょう。ごく基本的なテストの1つが、getterとsetterのテストです。通常こうしたテストでは、オブジェクトに設定した値がそのまま保持されてgetterで取り出せることを確認する必要があります。リスト1は、Addressオブジェクトのsetterとgetterを調べる単体テストの例です。

リスト1 典型的なgetter/setter単体テスト
/**
* This tests asserts that values stick to the
* Address object, via setters, and that the same
* values are accessible via the getters
*/
@Test
public void addressSetterGetterTest(){
//Create some test data
String firstName="Bob";
String lastName="Reselman";
String address1="The Waldorff-Astoria Hotel";
String address2="301 Park Avenue";
String city="New York";
String state="NY";
String zip="10022";

//Apply the data to the Address object
Address address = new Address();
address.setFirstName(firstName);
address.setLastName(lastName);
address.setAddress1(address1);
address.setAddress2(address2);
address.setCity(city);
address.setState(state);
address.setZip(zip);

//Make sure that the data stuck
Assert.assertEquals(address.getFirstName(), firstName);
Assert.assertEquals(address.getLastName(), lastName);
Assert.assertEquals(address.getAddress1(), address1);
Assert.assertEquals(address.getAddress2(), address2);
Assert.assertEquals(address.getCity(), city);
Assert.assertEquals(address.getState(), state);
Assert.assertEquals(address.getZip(), zip); 
}

 ごく単純な例ながら、リスト1の単体テストには、ありがちな落とし穴が潜んでいます。リスト1と次に示すコードから分かるように、ここではハードコーディングした値をAddressオブジェクトに代入しており、実際に作成したコードがこのテストにパスすることを確認しています。

//Create some test data
String firstName="Bob";
String lastName="Reselman";
String address1="The Waldorff-Astoria Hotel";
String address2="301 Park Avenue";
String city="New York";
String state="NY";
String zip="10022";

//Apply the data to the Address object
Address address = new Address();
address.setFirstName(firstName);
address.setLastName(lastName);
address.setAddress1(address1);
address.setAddress2(address2);
address.setCity(city);
address.setState(state);
address.setZip(zip);

 しかし結局のところ、このテストにパスするかどうかは、代入した値のみによる判断であり、他の値では確認していません。つまり、実装したコードがこのテストにパスしたとしても、"Bob"、"Reselman"、"The Waldorf-Astoria Hotel"、"301 Park Avenue"、"New York"、"NY"、"10022"という、ハードコーディングした少数のサンプルデータで正しく動作することが保証されたに過ぎないのです。

 開発者は、このテストは実際に作成するコードの動作を正確に反映したモデルだと想定しています。しかし、その想定には疑問の余地があります。例えば、今から1年後に別の開発者が現れて、AddressオブジェクトのsetFirstName(String name)メソッドでは6文字以上の名前をサポートしないことにするという奇妙な決定を下したとしたらどうなるでしょうか。回帰テストのとき、実際にはエラーとなる条件が存在するにもかかわらず、"Bob"というデータは問題なくパスしてしまうのです。

 もちろん、長期的に起こり得るあらゆる動作状況を1つ残らず網羅した単体テストを作成するのは困難ですし、現実に叶うものではありません。しかし、ハードコーディングのデータを使ったテストを作成するのと同じくらいの労力があれば、ランダム性を生かしたデータを使って、期待を裏切らないテストを実現することは可能です。

 リスト2は、リスト1の単体テストを改良したものです。QaRandomizerを使って、複数回の反復の中でランダムデータを生成しています。

リスト2 ランダム化と反復を利用したgetter/setter単体テスト
public void randomAddressSetterGetterTest() throws QaRandomizerException {
//Set the number of times to assign random data and 
//run the assertions
int numberOfTimesToTest = 10; 
for (int i = 0; i < numberOfTimesToTest; i++) { 
//Use the QaRandomizer to get some random address data 
RandomAddress randomAddress = QaRandomizer.getInstance().getAddress();
// Apply some random test data 
String firstName = QaRandomizer.getInstance().getFirstName(); 
String lastName = QaRandomizer.getInstance().getLastName();
String address1 = randomAddress.getAddressOne(); 
String address2 = randomAddress.getAddressTwo();
String city = randomAddress.getCity(); 
String state = randomAddress.getStateProvince(); 
String zip = randomAddress.getPostalCode();
// Apply the data to the Address object 
Address address = new Address();
address.setFirstName(firstName); 
address.setLastName(lastName);
address.setAddress1(address1); 
address.setAddress2(address2);
address.setCity(city); 
address.setState(state); 
address.setZip(zip); 
// Make sure that the data stuck
Assert.assertEquals(address.getFirstName(), firstName); 
Assert.assertEquals(address.getLastName(), lastName);
Assert.assertEquals(address.getAddress1(), address1);
Assert.assertEquals(address.getAddress2(), address2);
Assert.assertEquals(address.getCity(), city);
Assert.assertEquals(address.getState(), state);
Assert.assertEquals(address.getZip(), zip); 
// Print out some human readable data just for 
// visual satisfaction 
System.out.println(String.format("%s %s,
%s %s %s, %s %s ", firstName, lastName, address1, address2, city, state, zip));
} 
}

 QaRandomizerには、ファーストネーム(名)とラストネーム(姓)のデータをランダムに生成できる機能があります。また、標準的な形式のランダムな住所データを格納したRandomAddressオブジェクトも生成できます(RandomAddressオブジェクトの詳細については、QaRandomizerが持つメソッドの解説の中で説明します)。

 リスト2では、ファーストネーム、ラストネーム、住所の各データをランダムに生成するのみならず、テストを複数回(10回)繰り返しています。つまりこのコードでは、10組のランダムデータを生成してテストを実行し、10回パスしたということになります。当然ながら、確実性はその分高まります。

次のページ
QaRandomizerの機能

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Bob Reselman(Bob Reselman)

Edmunds Incのシニアテクニカルライター兼テクニカルエディター。Edmunds Inc.は、多彩な情報と高い可用性を誇る、最先端のJavaベースの各種自動車情報Webサイトを運営する大手パブリッシャーである。http://www.edmunds.com/およびhttp://www.insid...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4908 2010/03/03 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー