Menu

FrontPage

Eclipseプラグイン
Eclipse小技集
リファクタリング講座
テスティングフレームワーク JUnit
MSDEについて



The 20 newest affair
2010-09-092010-09-082010-09-072010-09-062010-09-012010-08-312010-08-272010-08-242010-08-232010-08-172010-08-162010-07-302010-07-212010-07-132010-06-272010-06-182010-06-172010-06-16









外部ファイルを読み込むHelloWorld  Λ


定数や文字列を外部ファイル化することが、よくあります。
HelloWorldを修正し、propertiesファイルから読み込んだ文字列を
コンソールに表示するプログラムを作成し、そのテストにチャレンジします。

HelloWorldは、多少ブサイクではありますが、下記のようになりました。

01 import java.util.ResourceBundle;
02 
03 public class HelloWorld {
04 
05   public static void main(String[] args) {
06     ResourceBundle resourceBundle = ResourceBundle.getBundle("HelloWorld");
07     String message = resourceBundle.getString("KEY");
08 
09     if ("".equals(message)) {
10       System.out.println("Message Not Found.");
11     else {
12       System.out.println(message);
13     }
14   }
15 
16 }

外部ファイルである、HelloWorld.propertiesは、

KEY=Hello World.

と一行書いておきます。

読み込み結果と分岐  Λ


「それらしい」テストにするため、HelloWorldには、あえて分岐を書きました。
ファイルから読み込んだメッセージが、「空文字だったら」という分岐です。

このHelloWorldのテストは、最低2パターン必要です。

  • メッセージが、正常に取得できたとき
  • 取得したメッセージが、空文字だったとき

しかし、メッセージを、ファイルから読み込んでいるため、上記2種類のテストを行うには、工夫が必要です。

たとえば、
    • HelloWorld.propertiesの内容を書き換える
    • propertiesファイルをテストパターンごとに準備し、テスト実行前にHelloWorld.propertiesにリネームする
    • 擬似オブジェクトを使用する

など、いろいろありそうです。

擬似オブジェクトを使用してテストする  Λ


ファイルの内容を書き換えたり、ファイル名をリネームしたり、ファイルの関係は、面倒くさそうなので、
擬似オブジェクトを使用して、なんとかしてみます。

ソース例

擬似オブジェクトを使用するために、HelloWorldを修正します。
考えたあげく、HelloWorldは、こんなんなりました。

01 import java.util.ResourceBundle;
02 
03 public class HelloWorld {
04 
05   public static void main(String[] args) {
06     HelloWorld world = new HelloWorld();
07     System.out.println(world.getMessage());
08   }
09 
10   String getMessage() {
11     ResourceBundle resourceBundle = getResourceBundle();
12     String string = resourceBundle.getString("KEY");
13 
14     return toMessage(string);
15   }
16 
17   ResourceBundle getResourceBundle() {
18     return ResourceBundle.getBundle("HelloWorld");
19   }
20 
21   private String toMessage(String message) {
22     if ("".equals(message)) return "Message Not Found.";
23     return message;
24   }
25 
26 }

getResourceBundle()が、ニセモノのResourceBundleオブジェクトを返却するようし、
getMessage()の返却値を検証すればよさそうです。

HelloWorldTestは、このようになりました。

01 import java.util.ListResourceBundle;
02 import java.util.ResourceBundle;
03 
04 import junit.framework.TestCase;
05 
06 public class HelloWorldTest extends TestCase {
07 
08   // 省略
09 
10   /** メッセージが、正常に取得できたときのテスト */
11   public void testMain001() {
12 
13     // getResourceBundle()をオーバーライドして、HelloWorldのインスタンスを生成
14     HelloWorld world = new HelloWorld() {
15       ResourceBundle getResourceBundle() {
16         // キーと値を仕込む。
17         // キー : "KEY"
18         // 値  : "Hello World."
19         return new ListResourceBundle() {
20           public Object[][] getContents() {
21             return new Object[][]{{"KEY""Hello World."}};
22           }
23         };
24       }
25     };
26 
27     assertEquals("Hello World.", world.getMessage());
28   }
29 
30   /** 取得したメッセージが、空文字だったときのテスト */
31   public void testMain002() {
32 
33     // getResourceBundle()をオーバーライドして、HelloWorldのインスタンスを生成
34     HelloWorld world = new HelloWorld() {
35       ResourceBundle getResourceBundle() {
36         // キーと値を仕込む。
37         // キー : "KEY"
38         // 値  : ""
39         return new ListResourceBundle() {
40           public Object[][] getContents() {
41             return new Object[][]{{"KEY"""}};
42           }
43         };
44       }
45     };
46 
47     assertEquals("Message Not Found.", world.getMessage());
48   }
49 }

疑似オブジェクトによる単体テスト(http://www-6.ibm.com/jp/developerworks/java/030207/j_j-mocktest.html)
では、このようなアプローチのことを言っているんでしょうか???

問題点


  • うまくリファクタリングしなければいけないため、プロジェクトメンバ全員が、同じ質のテストを書けそうにない
  • テストのパターンが増えたら、擬似オブジェクトの数が多くなり保守が大変そう
  • 慣れてないからかもしれませんが、正直いって、えらい疲れました。

djUnitを使用してテストする  Λ


djUnitで、チャレンジします。

テスト対象は、最初のままです。

01 import java.util.ResourceBundle;
02 
03 public class HelloWorld {
04 
05   public static void main(String[] args) {
06     ResourceBundle resourceBundle = ResourceBundle.getBundle("HelloWorld");
07     String message = resourceBundle.getString("KEY");
08 
09     if ("".equals(message)) {
10       System.out.println("Message Not Found.");
11     else 
12       System.out.println(message);
13     }
14   }
15 }

テストクラスは、こうなります。
HelloWorldの7行目、getString(String)の戻り値を、ニセモノに差し替えています。

01 import jp.co.dgic.testing.framework.DJUnitTestCase;
02 
03 public class HelloWorldTest extends DJUnitTestCase {
04 
05   // 省略
06 
07   /** メッセージが、正常に取得できたときのテスト */
08   public void testMain001() {
09 
10     // java.util.ResourceBundle#getStringの返却値として、"Hello World."をセットする
11     addReturnValue("java.util.ResourceBundle""getString""Hello World.");
12 
13     HelloWorld.main(null);
14 
15     assertArgumentPassed("java.io.PrintStream""println"0"Hello World.");
16   }
17 
18   /** 取得したメッセージが、空文字だったときのテスト */
19   public void testMain002() {
20 
21     // java.util.ResourceBundle#getStringの返却値として、空文字をセットする
22     addReturnValue("java.util.ResourceBundle""getString""");
23 
24     HelloWorld.main(null);
25 
26     assertArgumentPassed("java.io.PrintStream""println"0"Message Not Found.");
27   }
28 }

addReturnValueは、指定したメソッドの返却値を、好みのものに変更します。

void DJUnitTestCase#addReturnValue(String クラス名, String メソッド名, Object 返却値);

結論  Λ


djUnitでは、テスト対象のプログラムを修正することなく、また、擬似オブジェクトを作成することもなく、
擬似オブジェクトと同等なテストが可能になりそう。


Attached File: [Attached File All List]

Lastmodified: 2010-08-17 (火) 01:49:36 (23d)