テスト、というよりは「privateなメンバ変数の参照方法」とか「Reflectionの使い方」いった方がいいかも。いつか使う時が来ると思ったのでメモ。
通常、privateなメンバ変数をテストする場合は、getterの戻り値でテストしますが、getterが存在しない場合のテスト方法です。
例えば、次の仕様になっているコンストラクタが存在するとします。
- int型のメンバ変数を1つ持っている。
- コンストラクタの引数に整数を与えると、与えた整数の2倍の値がメンバ変数に格納される。
- 引数がない場合は、メンバ変数の値は0にする。
- getter/setterは存在しない(一度指定したら、外部から変更/参照ができない)。
まあ、こんなオブジェクトがあるかどうかはともかく・・・・・・。このような、getterのないオブジェクトをテストするには、Javaのリフレクションを使用します。
まずは、テスト対象のオブジェクトのソース。これは、仕様そのまま。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class PrivateTestProject { @SuppressWarnings("unused") private int mValue; /** * コンストラクタ */ public PrivateTestProject() { mValue = 0; } /** * コンストラクタ * @param value */ public PrivateTestProject(int value) { mValue = value * 2; } } |
続いて、JUnit側のソース。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import java.lang.reflect.Field; import junit.framework.TestCase; public class PrivateTestProjectTest extends TestCase { private PrivateTestProject mTestProject1; private PrivateTestProject mTestProject2; public PrivateTestProjectTest() { } @Override protected void setUp() throws Exception { // TODO Auto-generated method stub super.setUp(); mTestProject1 = new PrivateTestProject(); mTestProject2 = new PrivateTestProject(50); } /** * コンストラクタ(引数なし)のテストを実施する * @throws Exception */ @SuppressWarnings("unchecked") public void testPrivateTestProject1() throws Exception { //mTestProject1のクラスオブジェクトを取得する Class c = mTestProject1.getClass(); //PrivateTestProjectのmValueメンバ変数を取得する Field fld = c.getDeclaredField("mValue"); //取得したメンバ変数にアクセス権限を与える fld.setAccessible(true); assertEquals(0, ((Integer)fld.get(mTestProject1)).intValue()); } /** * コンストラクタ(引数あり)のテストを実施する */ @SuppressWarnings("unchecked") public void testPrivateTestProject2() throws Exception{ //mTestProject2のクラスオブジェクトを取得する Class c = mTestProject2.getClass(); //PrivateTestProjectのmValueメンバ変数を取得する Field fld = c.getDeclaredField("mValue"); //取得したメンバ変数にアクセス権限を与える fld.setAccessible(true); assertEquals(100, ((Integer)fld.get(mTestProject2)).intValue()); } } |
2つのコンストラクタに対してテストを行っていますが、判定が異なるだけで手順は同じです。
- クラスオブジェクトの取得
これは、インスタンスにgetClass()メソッドを呼び出して取得します。 - Fieldオブジェクトの取得
「PrivateTestProject」クラスの「mValue」を取得します。getField()は、publicはメンバ変数の取得しかできないので、 getDeclaredField()を使っています。 - アクセス権の付与
privateな変数はそのままではアクセスすることができないので、setAccessible()でアクセス権を付与しています。 - 実際の値の取得
2で取得したFieldオブジェクトに、3でアクセス権を付与したものに対して、get()を使ってメンバ変数を参照します。なお、get()の戻り値はObject()なので、今回の場合はIntegerオブジェクトにキャストしています。 - 判定
これまでの手順で、値を取得することができるようになったので、assertEquals()を使って判定します。
ピンバック: Whatever will be, will be. » 参考メモ