

よそから利用されないように`privateにしたフィールドA`があります。  
ですが、テストのためにそのフィールドにアクセスする必要が出てきました。  
そのために`java.lang.reflect`を用いてアクセスすることにしました。

そのフィールドは`テストしたい自作クラスB`の中にあり、`自作クラスC型の変数`です。  
また、プログラムの仕様上自作クラスBをテストするためには  
事前に`自作クラスCのインスタンス`を作ってセットしておく必要があります。

テストには **JUnit4** を使っていて、  
`setUp`内で`自作クラスCのインスタンス`を作ってセットしています。  
ですが、テスト中に`クラスB`が`クラスCのインスタンスがない`と言ってきます。

そこで、確認のために適当に作ったプログラムで  
privateなフィールドへの値セットと取得等を試してみました。

確認用に作ったSetCallTestクラス

[code]

    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();
            }
        }
    }
    
[/code]

自作クラスBの代わりのHasPrivateクラス

[code]

    package test;
    
    public class HasPrivate {
        private Nakami nakami;
        private Nakami arimasu=new Nakami();
    
        public Nakami getNakami(){
            return nakami;
        }
    
        public Nakami getArimasu(){
            return arimasu;
        }
    }
    
[/code]

自作クラスCの代わりのNakamiクラス

[code]

    package test;
    
    public class Nakami {
        public String nakami="中身";
    }
    
[/code]

`HasPrivate#arimasu`は`SetCallTest`から取得できますが、  
`HasPrivate#nakami`は`NullPointerException`になります。  
`SetCallTest`からセットできていないんだろうと思いつつ  
`HasPrivate`に`nakami`取得用のpublicなメソッドを用意して呼び出してみましたが、  
やはり同様です。

出力ログ

[code]

    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:中身
    
[/code]

* * *

確認用コード間違えすぎてすみません。  
本物のコードの一部抜粋したものを以下に載せます。

[code]

    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だと言われてしまう。*/
    }
    
[/code]

今本番の環境がないので本物のコードを試せないのですが、  
こういうことをやっていてうまくいかなくて  
JUnit4を使わずに試してみようと作ったのが確認用のプログラムです。  
そちらは適当すぎていろいろ間違えていましたが、きちんと動作するよう修正したコードは  
これとやっていることはそんな変わらないと思うのですが、  
本物ではなにかやり方を間違えているのでしょうか？


CC BY-SA 3.0
2015-08-28T10:41:28.250
14956
2015-08-31T03:02:04.103
2015-08-31T03:02:04.103
49
9710
question
java junit
privateなフィールドに値をセットしたいのですがうまく行きません


`setNakami`、`getNakami`、`getArimasu`の各メソッドにはそれぞれ

[code]

    HasPrivate hasPrivate = new HasPrivate();
    
[/code]

という行がありますが、この`hasPrivate`はそれぞれ別のオブジェクトになっています。

[code]

    setNakami(nakami);
    
[/code]

と呼び出すと、`HasPrivate`オブジェクトが作成され、`nakami`がプライベートなフィールドにセットされますが、
**`setNakami`の呼び出しの終了とともに、せっかくプライベートなフィールドに`nakami`をセットした`HasPrivate`オブジェクトが破棄されています。**
そして、次の

[code]

    getNakami(nakami);
    
[/code]

の呼び出しでは、先ほど`setNakami(nakami);`でフィールドにセットしたオブジェクトとは異なる`HasPrivate`オブジェクトを改めて作り直しており、新たに作られた`HasPrivate`オブジェクトの`nakami`フィールドは作りたてなので`null`のままで、そのため、

[code]

    Nakami nakami2 = (Nakami) privateField.get(hasPrivate);
    
[/code]

としてフィールドを読み取っても`nakami2`は`null`になります。

`setNakami`、`getNakami`、`getArimasu`の各メソッドでそれぞれ別の`HasPrivate`オブジェクトを使っており、`setNakami`を呼び出した意味がなくなってしまっているのが原因だと思われます。

おそらくですが、このようなことがしたいのではないでしょうか：  
<https://ideone.com/w3Xui9>


CC BY-SA 3.0
2015-08-28T11:17:26.977
14959
2015-08-28T11:20:35.843
2015-08-28T11:20:35.843
10330
10330
14956
answer


メソッド setNakami() の先頭にある

[code]

    HasPrivate hasPrivate = new HasPrivate();
    
[/code]

を

[code]

    hasPrivate = new HasPrivate();
    
[/code]

にすることで、提示していただいたコードは動作します。

ですがこれはJUnit4を使うことなく、Javaをそのまま実行しても動作するコードですね。  
JUnitを利用する前提として、動作しているクラスやメソッドに対して、JUnit用のクラスを用意して実行するもので、そして実行結果を評価するものです。

JUnit4に関しては簡単なサンプルコードとして以下のサイトがあります。  
<http://nanasess.net/mt/2008/04/junit4.html>

JUnit4の使い方とできることを簡単にまとめているスライドです。  
<http://www.slideshare.net/ichikaz3/junit4>

これらも参考にしてください。


CC BY-SA 3.0
2015-08-29T00:53:01.780
14984
2015-08-29T00:53:01.780
5778
14956
answer


本日実際のコードを確認したところ、  
うまく行かなかったのはreflectするときにクラスを間違えていたからでした。  
きちんと確認していれば気がつけたミスですみません。  

[code]

    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.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    import com.example.sakaguchi.model.PriceItem;
    import com.example.sakaguchi.model.PriceListData;
    import com.example.sakaguchi.model.PriceListDataLoader;
    
    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() {
            mPriceListDataLoader = new PriceListDataLoader();
    
            try {
                mPriceListData = new PriceListData();
                Field field = PriceListDataLoader.class.getDeclaredField("mPriceListData");
                //ここをPriceListDataLoaderではなく誤ってPriceListDataと書いてしまっていた。
                field.setAccessible(true);
                field.set(mPriceListDataLoader, mPriceListData);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            try {
                //json作成
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    
        /*以下テスト用メソッドが続く。
        * mPriceListDataLoaderのこれまたprivateなメソッドを呼び出す。
        * そのメソッドは引数のjsonからデータを取得・加工したものをPriceListDataに入れる。
        * そのPriceListDataをチェックして想定通りのデータが入っているかどうか確認する。*/
    }
    
[/code]


CC BY-SA 3.0
2015-08-31T00:32:13.197
15059
2015-08-31T00:32:13.197
9710
14956
answer