JavaのPrivateメソッドやフィールドにアクセスする方法


主に自分が不甲斐ないせいでJavaを2週間くらい放置していたのですが、開発も佳境に突入しいざJUnitでテストすんべ!と奮い立ち、アクセス修飾子がPrivateのメソッドやフィールド変数を使おうとしても当然のごとく他クラスからは呼べないわけで( ^ω^)・・・

でもまぁいろいろ調べてみたらできちゃったのでメモっておきます。
よかったら肥やしにしてみてください。

使用環境:
OS:Windows 10
java ver:8
IDE:eclipse 4.6 Neon

Jarファイルをダウンロードしよう

外部サイト(https://ja.osdn.net/projects/sfnet_junit-addons/releases/)
からjunit-addonsのJarファイルを入手します。

てきとーなローカルディレクトリに保存してください。

Jarファイルを追加しよう

eclipseを起動し、[パッケージ・エクスプローラ]上で右クリックし、[ビルド・パス]→[ビルドパスの構成]→[javaのビルド・パス]から外部Jarを追加します。

これで準備完了。

ちなみにAPI仕様はどんな感じ?

ふむふむ。

さっぱりわかんねぇ。

おしえてぐーぐるせんせー!

ごちゃごちゃ動かす

テストプログラムを用意します。
まずはテスト対象のプログラムから。

Sample.java
public class Sample {

//  privateなフィールド変数
    private int x = 10;

//  privateでstaticなフィールド変数
    private static int y = 20;

//  privateなメソッド
    private String testMethod(String x){

        return x;
    }

//  privateでstaticなメソッド
    private static String testStaticMethod(String y, String z){

        return y + z;
    }

}

次にJUnit用にクラスファイルを用意します。

SampleTest.java
import static org.junit.Assert.*;

import org.junit.Test;

import junitx.util.PrivateAccessor;

public class SampleTest {

    @Test
    /**
     * privateのフィールド、メソッドにアクセスするテスト関数
     */
    public void privateGetField() throws Throwable {
        Sample sample = new Sample();

        try {

//          privateなフィールド変数にアクセスするためのメソッド。
//          第一引数:テスト対象クラスのインスタンス変数 第二引数:アクセスしたいフィールド変数名
            int x = (int)PrivateAccessor.getField(sample, "x");

//          アサーションにより実測値と期待値を比較
            assertEquals(x,10);

//          privateでstaticなフィールド変数も同様の手法でアクセスできる。説明省略
            int y = (int)PrivateAccessor.getField(sample, "y");
            assertEquals(y,20);


//          privateな関数にアクセスするためのメソッド。
//          第一引数:テスト対象クラスのインスタンス変数 第二引数:アクセスしたいフィールド関数名
//          第三引数:引数の型の配列 第四引数:引数の値の配列
            String method_x = (String)PrivateAccessor.invoke(   sample,
                                                                "testMethod",
                                                                new Class[]{String.class},
                                                                new Object[]{"private_x"});
            assertEquals(method_x,"private_x");

//          privateでstaticな関数も同様の手法でアクセスできる。引数の型の数に応じて第三、第四引数を工夫すること
            String method_y = (String)PrivateAccessor.invoke(   sample,
                                                                "testStaticMethod",
                                                                new Class[]{String.class,String.class},
                                                                new Object[]{"private_","static_y"});
            assertEquals(method_y,"private_static_y");


        } catch (NoSuchFieldException e) {

            e.printStackTrace();

        }finally{

        }
    }
}

実行

どや!

できた!

 おまけ

privateなフィールド変数に値をセットすることもできちゃったり。

SampleTest.java

//途中省略

    @Test
    /**
     * privateなフィールド変数に値をセットする関数
     */
    public void privateSetField(){

        Sample sample = new Sample();

        try {

//          第一引数:テスト対象クラスのインスタンス変数 第二引数:変数の名前
//          第三引数: セットしたい値
            PrivateAccessor.setField(sample, "x", 100);

//          セットできたか確認!
            int get_x = (int)PrivateAccessor.getField(sample, "x");
            assertEquals(get_x,100);

        } catch (NoSuchFieldException e) {

            e.printStackTrace();

        }finally{

        }
    }


おわりっ