privateなフィールドに値をセットしたいのですがうまく行きません
よそから利用されないようにprivateにしたフィールドA
があります。
ですが、テストのためにそのフィールドにアクセスする必要が出てきました。
そのためにjava.lang.reflect
を用いてアクセスすることにしました。
そのフィールドはテストしたい自作クラスB
の中にあり、自作クラスC型の変数
です。
また、プログラムの仕様上自作クラスBをテストするためには
事前に自作クラスCのインスタンス
を作ってセットしておく必要があります。
テストにはJUnit4を使っていて、
setUp
内で自作クラスCのインスタンス
を作ってセットしています。
ですが、テスト中にクラスB
がクラスCのインスタンスがない
と言ってきます。
そこで、確認のために適当に作ったプログラムで
privateなフィールドへの値セットと取得等を試してみました。
確認用に作ったSetCallTestクラス
package test;
import java.lang.reflect.Field;
public class SetCallTest {
private HasPrivate hasPrivate;
private Nakami nakami;
public static void main(String[] args) {
SetCallTest test = new SetCallTest();
System.out.println("Nakamiをセットします。");
test.setNakami();
System.out.println("セットしたNakamiを取得します。");
test.getNakami();
System.out.println("もともと入れてあるNakamiを取得します。");
test.getArimasu();
}
public SetCallTest() {
hasPrivate = new HasPrivate();
nakami = new Nakami();
}
public void setNakami() {
try {
Field privateField = HasPrivate.class.getDeclaredField("nakami");
privateField.setAccessible(true);
privateField.set(hasPrivate, nakami);
} catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
public void getNakami() {
try {
Field privateField = HasPrivate.class.getDeclaredField("nakami");
privateField.setAccessible(true);
Nakami nakami2 = (Nakami) privateField.get(hasPrivate);
System.out.println("取得したnakami:" + nakami2);
System.out.println("HasPrivateからもらったnakami:" + hasPrivate.getNakami());
System.out.println("Nakamiのnakami:" + nakami2.nakami);
} catch (Exception e) {
e.printStackTrace();
}
}
public void getArimasu() {
try {
Field arimasu = HasPrivate.class.getDeclaredField("arimasu");
arimasu.setAccessible(true);
Nakami nakami2 = (Nakami) arimasu.get(hasPrivate);
System.out.println("取得したarimasu:" + nakami2);
System.out.println("HasPrivateからもらったariamsu:" + hasPrivate.getArimasu());
System.out.println("arimasuのnakami:" + nakami2.nakami);
} catch (Exception e) {
e.printStackTrace();
}
}
}
自作クラスBの代わりのHasPrivateクラス
package test;
public class HasPrivate {
private Nakami nakami;
private Nakami arimasu=new Nakami();
public Nakami getNakami(){
return nakami;
}
public Nakami getArimasu(){
return arimasu;
}
}
自作クラスCの代わりのNakamiクラス
package test;
public class Nakami {
public String nakami="中身";
}
HasPrivate#arimasu
はSetCallTest
から取得できますが、
HasPrivate#nakami
はNullPointerException
になります。
SetCallTest
からセットできていないんだろうと思いつつ
HasPrivate
にnakami
取得用のpublicなメソッドを用意して呼び出してみましたが、
やはり同様です。
出力ログ
Nakamiをセットします。
セットしたNakamiを取得します。
取得したnakami:test.Nakami@6d06d69c
HasPrivateからもらったnakami:test.Nakami@6d06d69c
Nakamiのnakami:中身
もともと入れてあるNakamiを取得します。
取得したarimasu:test.Nakami@7852e922
HasPrivateからもらったariamsu:test.Nakami@7852e922
arimasuのnakami:中身
確認用コード間違えすぎてすみません。
本物のコードの一部抜粋したものを以下に載せます。
package com.example.sakaguchi.test.all.model;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Method;
import java.util.ArrayList;
import com.example.sakaguchi.model.PriceItem;
import com.example.sakaguchi.model.PriceListDataLoader;
import com.example.sakaguchi.model.PriceListData;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* PhotoListDataのテスト.
* ダミーのjsonを渡してそれ通りにデータを取得等できるかをテストする。
* 現状はとりあえず以下の3パターン。
* ・集合写真
* ・スナップ写真・データ販売あり・現像販売あり
* ・セッション切れ
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
public class PriceListDataLoaderTest {
PriceListDataLoader mPriceListDataLoader;
PriceListData mPriceListData;
JSONObject mPriceListJson, mSessionOutJson;
@Before
public void setUp() {
mPriceListData = new PriceListDataLoader();
mPriceListData = new PriceListData();
Field priceListData = HasPrivate.class.getDeclaredField("mPriceListData");
priceListData.setAccessible(true);
priceListData.set(mPriceListDataLoader, mPriceListData);
try {
//json作成
} catch (JSONException e) {
e.printStackTrace();
}
}
/*以下テスト用メソッドが続く。
* mPriceListDataLoaderのこれまたprivateなメソッドを呼び出す。
* そのメソッドは引数のjsonからデータを取得・加工したものをPriceListDataに入れる。
* そのPriceListDataをチェックして想定通りのデータが入っているかどうか確認したい。
* ですが、そもそもsetUpでmPriceListDataLoaderに設定したはずの
* mPriceListDataがnullだと言われてしまう。*/
}
今本番の環境がないので本物のコードを試せないのですが、
こういうことをやっていてうまくいかなくて
JUnit4を使わずに試してみようと作ったのが確認用のプログラムです。
そちらは適当すぎていろいろ間違えていましたが、きちんと動作するよう修正したコードは
これとやっていることはそんな変わらないと思うのですが、
本物ではなにかやり方を間違えているのでしょうか?