1. Top
  2. Java Tips
  3. JUnit

JUnitでprivateなメソッドをテストする

JUnitなどでprivateなメソッドを試験したいときがあります。当然ながら、privateメソッドはテストケースから直接呼び出すことはできません。
リフレクションクラスを利用してprivateメソッドをテストすることは可能であるが、junit-addons.jarのPrivateAccessorクラスを用いてprivateメソッドをテストすることができます。


junit-addons.jar のダウンロードURLはこちらです。



【privateメソッドを呼び出すためのユーティリティクラス】
package test.com;

import junitx.util.PrivateAccessor;

/**
 * privateメソッドを呼び出すためのユーティリティクラス。
 * 
 * @author livetp.com
 */
public class PrivateAccessUtil {

    /**
     * privateメソッドを呼び出す。(staticでないもの)★1★
     * パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、
     * そちらを利用した方がシンプルに記述できる。
     * 
     * @param target 呼び出す対象のオブジェクト
     * @param methodName 呼び出したいメソッドの名前
     * @param argTypes 引数の型の配列
     * @param args 引数の値の配列。
     * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに
     * 格納して値を渡す必要あり。
     * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。
     * int, boolean等の基本データ型は、Integer, Boolean等の
     * ラッパークラスに格納されて値が戻される。
     * @throws Exception
     */
    public static Object invokePrivate(Object target, String methodName,
            Class[] argTypes, Object[] args) throws Exception {
        
        // JUnit Addonsのメソッドを呼び出す。
        Object val = null;
        try {
            val = PrivateAccessor.invoke(target, methodName, argTypes, args);
        } catch (Throwable t) {
            Exception e = (Exception) t;
            throw e;
        }
        return val;
    }

    /**
     * privateメソッドを呼び出す。(staticでないもの)(パラメータ0個用)
     * 
     * @param target 呼び出す対象のオブジェクト
     * @param methodName 呼び出したいメソッドの名前
     * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。
     * int, boolean等の基本データ型は、Integer, Boolean等の
     * ラッパークラスに格納されて値が戻される。
     * @throws Exception
     */
    public static Object invokePrivate(Object target, String methodName)
        throws Exception {

        return invokePrivate(target, methodName, 
            new Class[] {}, new Object[] {});
    }

    /**
     * privateメソッドを呼び出す。(staticでないもの)(パラメータ1個用)
     * 
     * @param target 呼び出す対象のオブジェクト
     * @param methodName 呼び出したいメソッドの名前
     * @param argType 引数の型
     * @param arg 引数の値。
     * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに
     * 格納して値を渡す必要あり。
     * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。
     * int, boolean等の基本データ型は、Integer, Boolean等の
     * ラッパークラスに格納されて値が戻される。
     * @throws Exception
     */
    public static Object invokePrivate(Object target, String methodName,
            Class argType, Object arg) throws Exception {

        return invokePrivate(target, methodName,
            new Class[] { argType }, new Object[] { arg });
    }

    /**
     * privateメソッドを呼び出す。(staticでないもの)(パラメータ2個用)
     * 
     * @param target 呼び出す対象のオブジェクト
     * @param methodName 呼び出したいメソッドの名前
     * @param argType1 第一引数の型
     * @param argType2 第二引数の型
     * @param arg1 第一引数の値。
     * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに
     * 格納して値を渡す必要あり。
     * @param arg2 第二引数の値。
     * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。
     * int, boolean等の基本データ型は、Integer, Boolean等の
     * ラッパークラスに格納されて値が戻される。
     * @throws Exception
     */
    public static Object invokePrivate(Object target, String methodName,
            Class argType1, Class argType2, Object arg1, Object arg2)
            throws Exception {

        return invokePrivate(target, methodName,
            new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 });
    }


    /**
     * privateメソッドを呼び出す。(staticメソッド)★2★
     * 

* パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、 * そちらを利用した方がシンプルに記述できる。 * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argTypes 引数の型の配列 * @param args 引数の値の配列。 * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに * 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 * int, boolean等の基本データ型は、Integer, Boolean等の * ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokeStaticPrivate( Class target, String methodName, Class[] argTypes, Object[] args) throws Exception { // JUnit Addonsのメソッドを呼び出す。 Object val = null; try { val = PrivateAccessor.invoke(target, methodName, argTypes, args); } catch (Throwable t) { Exception e = (Exception) t; throw e; } return val; } /** * privateメソッドを呼び出す。(staticメソッド)(パラメータ0個用) * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 * int, boolean等の基本データ型は、Integer, Boolean等の * ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokeStaticPrivate( Class target, String methodName) throws Exception { return invokeStaticPrivate(target, methodName, new Class[] {}, new Object[] {}); } /** * privateメソッドを呼び出す。(staticメソッド)(パラメータ1個用) * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType 引数の型 * @param arg 引数の値。 * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに * 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 * int, boolean等の基本データ型は、Integer, Boolean等の * ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokeStaticPrivate( Class target, String methodName, Class argType, Object arg) throws Exception { return invokeStaticPrivate(target, methodName, new Class[] { argType }, new Object[] { arg }); } /** * privateメソッドを呼び出す。(staticメソッド)(パラメータ2個用) * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType1 第一引数の型 * @param argType2 第二引数の型 * @param arg1 第一引数の値。 * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに * 格納して値を渡す必要あり。 * @param arg2 第二引数の値。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 * int, boolean等の基本データ型は、Integer, Boolean等の * ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokeStaticPrivate(Class target, String methodName, Class argType1, Class argType2, Object arg1, Object arg2) throws Exception { return invokeStaticPrivate(target, methodName, new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 }); } /** * privateフィールドの値を取得する。★3★ * * @param target 対象のオブジェクト * @param fieldName 値を取得するprivateフィールドの名前 * @return privateフィールドの値 * @exception NoSuchFieldException */ public static Object getField(Object target, String fieldName) throws NoSuchFieldException { // JUnit Addonsのメソッドを呼び出す。 return PrivateAccessor.getField(target, fieldName); } /** * privateフィールドの値を取得する。(static変数)★4★ * * @param target 対象のクラス * @param fieldName 値を取得するprivateフィールドの名前 * @return privateフィールドの値 * @exception NoSuchFieldException */ public static Object getStaticField(Class target, String fieldName) throws NoSuchFieldException { // JUnit Addonsのメソッドを呼び出す。 return PrivateAccessor.getField(target, fieldName); } /** * privateフィールドに値を設定する。★5★ * * @param target 対象のオブジェクト * @param fieldName 値を設定するprivateフィールドの名前 * @param value 設定する値。 * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに * 格納して値を渡す必要あり。 * @exception NoSuchFieldException */ public static void setField( Object target, String fieldName, Object value) throws NoSuchFieldException { // JUnit Addonsのメソッドを呼び出す。 PrivateAccessor.setField(target, fieldName, value); } /** * privateフィールドに値を設定する。(static変数)★6★ * * @param target 対象のクラス * @param fieldName 値を設定するprivateフィールドの名前 * @param value 設定する値。 * int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに * 格納して値を渡す必要あり。 * @exception NoSuchFieldException */ public static void setStaticField( Class target, String fieldName, Object value) throws NoSuchFieldException { // JUnit Addonsのメソッドを呼び出す。 PrivateAccessor.setField(target, fieldName, value); } /** * privateなコンストラクタ。 */ private PrivateAccessUtil() { } }


【テスト対象ラス】
package test.sample;

/**
 * @author livetp.com
 */
public class Target {

    /** privateフィールド */
    private String field1 = "aaa";
    
    /** staticなprivateフィールド */
    private static String field2 = "bbb";
    
    /**
     * privateメソッド
     */
    @SuppressWarnings("unused")
    private String getField1() {
        return field1;
    }
    
    @SuppressWarnings("unused")
    private void setField1(String field1) {
        this.field1 = field1;
    }

    /**
     * staticなprivateメソッド
     */
    @SuppressWarnings("unused")
    private static String getField2() {
        return field2;
    }

    @SuppressWarnings("unused")
    private static void setField2(String field2) {
        Target.field2 = field2;
    }
}



privateメソッドを呼び出す。(staticでないもの)

private メソッドにアクセスする場合、
PrivateAccessUtilの invokePrivate メソッドを利用するする。
以下はサンプルテストケースです。
package test.sample;

import static org.junit.Assert.*;
import org.junit.Test;
import test.com.PrivateAccessUtil;

/**
 * @author livetp.com
 */
public class testPrivateMethod {
    
    /**
     * privateメソッドを呼び出す。(staticでないもの)
     */
    @Test
    public void testGetField1() {
        // テスト対象オブジェクト
        Target target = new Target();
        
        try {
            // privateメソッドを呼び出して、メンバ変数の値を変更する。
            PrivateAccessUtil.invokePrivate(
                    target,             // テスト対象オブジェクト
                    "setField1",        // メソッド名
                    String.class,       // メソッド引数の型
                    "111");             // メソッド引数
            
            // privateメソッドを呼び出して、変更した値を取得する。
            String value = (String) PrivateAccessUtil.invokePrivate(
                    target,             // テスト対象オブジェクト
                    "getField1");       // メソッド名
            
            assertEquals("111", value);
            
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }
}


ページの先頭へ

privateメソッドを呼び出す。(staticメソッド)

staticなprivate メソッドにアクセスする場合、
PrivateAccessUtilの invokeStaticPrivate メソッドを利用するする。
以下はサンプルテストケースです。
package test.sample;

import static org.junit.Assert.*;
import org.junit.Test;
import test.com.PrivateAccessUtil;

/**
 * @author livetp.com
 */
public class testPrivateMethod {
    
    /**
     * privateメソッドを呼び出す。(staticメソッド)
     */
    @Test
    public void testStaticPrivateMethod() {
        // テスト対象オブジェクト
        Target target = new Target();
        
        try {
            // staticなprivateメソッドを呼び出して、メンバ変数の値を変更する。
            PrivateAccessUtil.invokeStaticPrivate(
                    target.getClass(),  // テスト対象オブジェクト
                    "setField2",        // メソッド名
                    String.class,       // メソッド引数の型
                    "222");             // メソッド引数
            
            // staticなprivateメソッドを呼び出して、変更した値を取得する。
            String value = (String) PrivateAccessUtil.invokeStaticPrivate(
                    target.getClass(),  // テスト対象オブジェクト
                    "getField2");       // メソッド名
            
            assertEquals("222", value);
            
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }
}



ページの先頭へ

privateフィールドの値を取得する。

private 変数の値を取得場合、
PrivateAccessUtilの getField メソッドを利用するする。
以下はサンプルテストケースです。
	/**
	 * privateフィールドの値を取得する。
	 */
	@Test
	public void testGetPrivateField() {
	    // テスト対象オブジェクト
	    Target target = new Target();
	    
	    try {
	        // privateフィールドの値を取得する。
	        String value = (String) PrivateAccessUtil.getField(
	                target,         // テスト対象オブジェクト
	                "field1");      // フィールド名
	        
	        assertEquals("aaa", value);
	        
	    } catch (Exception e) {
	        e.printStackTrace();
	        fail();
	    }
	}


ページの先頭へ

privateフィールドの値を取得する。(static変数)

staticなprivate 変数の値を取得する場合、
PrivateAccessUtilの getStaticField メソッドを利用するする。
以下はサンプルテストケースです。
    /**
     * privateフィールドの値を取得する。(static変数)
     */
    @Test
    public void testGetStaticPrivateField() {
        // テスト対象オブジェクト
        Target target = new Target();
        
        try {
            // staticなprivateフィールドの値を取得する。
            String value = (String) PrivateAccessUtil.getStaticField(
                    target.getClass(),  // テスト対象オブジェクト
                    "field2");          // フィールド名
            
            assertEquals("bbb", value);
            
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }


ページの先頭へ

privateフィールドに値を設定する。

private 変数にアクセスする場合、
PrivateAccessUtilの setField メソッドを利用するする。
以下はサンプルテストケースです。
    /**
     * privateフィールドに値を設定する。
     */
    @Test
    public void testSetPrivateField() {
        // テスト対象オブジェクト
        Target target = new Target();
        
        try {
            // privateフィールドの値を取得する。
            PrivateAccessUtil.setField(
                    target,         // テスト対象オブジェクト
                    "field1",       // フィールド名
                    "111");         // 値
            
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }


ページの先頭へ

privateフィールドに値を設定する。(static変数)

staticなprivate 変数にアクセスする場合、
PrivateAccessUtilの setStaticField メソッドを利用するする。
以下はサンプルテストケースです。
    /**
     * privateフィールドに値を設定する。(static変数)
     */
    @Test
    public void testSetStaticPrivateField() {
        // テスト対象オブジェクト
        Target target = new Target();
        
        try {
            // privateフィールドの値を取得する。
            PrivateAccessUtil.setStaticField(
                    target.getClass(),  // テスト対象オブジェクト
                    "field2",           // フィールドの型
                    "222");             // 値
            
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }


ページの先頭へ