マイナー・マイナー

隠れた名作の発掘が生きがい。

privateなフィールドを直接参照してgetterとsetterをテストする


スポンサードリンク

単体テストでゲッター(getter)とセッター(setter)の動作確認をしなければならないことがあります*1.それらは構造が単純なので,ただデバッグによる目視確認でよいだけだと思いますが,それらが大量にある場合はデバッグでそれらを一つ一つ確認するのは手間がかかるので,なんとかスマートに確認したい.また,確認したというエビデンスも残しておきたい.そんなわけで,JUnitでgetterとsetterの動作を確認するテストコードを作りました.


まず,テスト対象となるクラスとして,getterとsetterを実装した次のUnitクラスを想定します.

public class Unit {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


次に,getterとsetterの動作は,それぞれ次の手順を踏めば確認できたと見なせそうです.
getter
(A-1)nameフィールドに直接アクセスしてname値をセットする.
(A-2)getNameメソッドを呼び出してゲットした値と,(A-1)でセットした値とが等しいか確認する.


setter
(B-1)setNameメソッドを呼び出して,nameの値をセットする.
(B-2)nameフィールドに直接アクセスしてゲットした値と,(B-1)でセットした値とが等しいか確認する.


確認のためにはprivateなnameフィールドを参照する必要があります.privateは外部クラスからは参照することができないと学んできたのですが,なんとリフレクションを使えば参照することができるようです.リフレクションとは,クラスからフィールドやメソッドといった情報を取得するAPIです.privateなフィールド情報から値をセット/ゲットするには次の手順が必要です.


(1)クラスからフィールド情報を取得する.
java.lang.classのgetDeclaredFieldメソッドを使用します.引数には取得したいフィールド名(String)を指定します.戻り値はjava.lang.reflect.Fieldなので,その型でフィールド情報を保持します.


(2)フィールド情報にアクセスできるようにする.
FieldクラスのsetAccessibleメソッドを使用します.引数にtrueを指定することで,フィールド情報にアクセスできるようになります.


(3)フィールド情報から値をセット/ゲットする.
セット/ゲットはそれぞれFieldクラスのset/getメソッドを使います.setは,第一引数にフィールド情報を持つクラスオブジェクト,第二引数に設定したい値を指定します.getは引数にフィールド情報を持つクラスオブジェクトを指定することでフィールド値をゲットすることができますが,戻り値はオブジェクト型なので必要に応じてキャストする必要があります.


これらのコードを実装したgetterとsetterのテストコードは次のようになります.テストはJUnit 4を利用しました.フィールド参照に関わるメソッドは例外をスローする可能性があるので,使用する側でExceptonをスローしました.

import static org.junit.Assert.*;
import java.lang.reflect.Field;
import org.junit.Test;

public class UnitTest {

       @Test
       public void testGetName() throws Exception{
               Unit unit = new Unit();
               String name = new String("Unit Test");
               
               //(A-1)
               Field nameField = unit.getClass().getDeclaredField("name"); //(1)
               nameField.setAccessible(true);	//(2)
               nameField.set(unit, name);	//(3)
               
               //(A-2)
               assertEquals(name, unit.getName());
       }

       @Test
       public void testSetName() throws Exception{
               Unit unit = new Unit();
               String name = new String("Unit Test");

               //(B-1)
               Field nameField = unit.getClass().getDeclaredField("name"); //(1)
               nameField.setAccessible(true);	//(2)
               unit.setName(name);
               
               //(B-2)
               assertEquals(name, (String)nameField.get(unit));	//(3)
       }
}


実行結果はすべてグリーンでした.

*1:getterとsetterのテストする必要があるのか疑問ですが,品質確保といいますか,テスト項目のかさ増しと言いますか,大人な事情でテストする必要があるのです.