JUnitでprivateなメンバ変数をテストする

テスト、というよりは「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つのコンストラクタに対してテストを行っていますが、判定が異なるだけで手順は同じです。

  1. クラスオブジェクトの取得
    これは、インスタンスにgetClass()メソッドを呼び出して取得します。
  2. Fieldオブジェクトの取得
    「PrivateTestProject」クラスの「mValue」を取得します。getField()は、publicはメンバ変数の取得しかできないので、 getDeclaredField()を使っています。
  3. アクセス権の付与
    privateな変数はそのままではアクセスすることができないので、setAccessible()でアクセス権を付与しています。
  4. 実際の値の取得
    2で取得したFieldオブジェクトに、3でアクセス権を付与したものに対して、get()を使ってメンバ変数を参照します。なお、get()の戻り値はObject()なので、今回の場合はIntegerオブジェクトにキャストしています。
  5. 判定
    これまでの手順で、値を取得することができるようになったので、assertEquals()を使って判定します。
カテゴリー: Java パーマリンク

JUnitでprivateなメンバ変数をテストする への1件のフィードバック

  1. ピンバック: Whatever will be, will be. » 参考メモ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です