JUnitでprivate scopeなものをテストする方法
private scopeなものをテストする
Javaでprivate scopeのフィールド、メソッド、内部クラスを外部から呼び出し、
JUnitでテストしてみます。
※何番煎じか、出涸らしかという記事です。
まず、JUnitでテストしようとしてみます。
コンパイルエラーです。仕様です。実行できません。
privateなので、publicと同じようには呼び出せません。
そこでReflectionを使ってprivate scopeなものを呼び出します。
Reflectionとは
Reflectionとは、Javaの標準ライブラリの一種で
クラスそのものの情報を扱うことです。
具体的な例として、
クラス名、メソッド名、フィールド名の文字列で
そのクラスを生成、メソッド実行、フィールドへのアクセスが
できたりします。
以下、外部サイトですが、例えばこんな感じです。
http://java.keicode.com/lang/reflection.php
「こんなに便利なら積極的に使おう」
と思う方もいるかもしれません。
ですが、Reflectionは諸刃の剣です。取扱厳重注意です。
しかし、敢えて紹介します。
Reflectionの問題点
Reflectionは使い方次第で
- クラス設計が崩壊する
- コードが書きにくいし読みにくくなる
- パフォーマンスが普通にメソッドを呼び出すより悪い
など、問題点もあります。
しかし、敢えて紹介します。
「JUnitでprivate scopeなものをテストする」
という限定した目的で使うためです。
本題に戻って
さっきのエラーだらけのJUnitのテストクラスを直してみます。
package jp.co.illmatics.sample;
/**
* テスト対象のクラス
*/
@SuppressWarnings("unused")
public class PrivateSample {
private String field = "Hello field!";
private final String finalField = "Hello final field!";
private String doIt() {
return "Hello method!";
}
private class InnerClass {
public InnerClass() {
}
public String getInnerMethod() {
return "Hello inner method!";
}
}
}
package jp.co.illmatics.sample;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Test;
import junit.framework.TestCase;
/**
* テストクラス
*/
public class PrivateSampleTest extends TestCase {
PrivateSample privateSample = new PrivateSample();
String expected = "";
String actual = "";
@Test
public void testField() throws Exception {
final String fieldName = "field";
expected = "Hello field!";
actual = (String) getFieldValue(privateSample, fieldName);
assertEquals(expected, actual);
}
@Test
public void testFinalField() throws Exception {
final String finalFieldName = "finalField";
expected = "Hello updated final Field!";
actual = (String) getUpdatedFinalFieldValue(privateSample, expected, finalFieldName);
assertEquals(expected, actual);
}
@Test
public void testMethod() throws Exception {
final String methodName = "doIt";
expected = "Hello method!";
actual = (String) getMethodValue(privateSample, methodName);
assertEquals(expected, actual);
}
@Test
public void testInnerClassMethod() throws Exception {
final String innerClassName = "jp.co.illmatics.sample.PrivateSample$InnerClass";
final String innerMethodName = "getInnerMethod";
expected = "Hello inner method!";
actual = (String) getInnerClassMethod(privateSample, innerClassName, innerMethodName);
assertEquals(expected, actual);
}
private Object getFieldValue(PrivateSample privateSample, String fieldName)
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
SecurityException {
return getPrivateField(privateSample, fieldName).get(privateSample);
}
private Field getPrivateField(PrivateSample privateSample, String fieldName)
throws NoSuchFieldException, SecurityException, IllegalArgumentException,
IllegalAccessException {
Class<?> clazz = privateSample.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
}
private Object getUpdatedFinalFieldValue(PrivateSample privateSample, String newValue,
String fieldName) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field finalField = getPrivateField(privateSample, fieldName);
finalField.set(privateSample, newValue);
return finalField.get(privateSample);
}
private Object getMethodValue(PrivateSample privateSample, String name)
throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Method doIt = PrivateSample.class.getDeclaredMethod(name);
doIt.setAccessible(true);
return doIt.invoke(privateSample);
}
private Object getInnerClassMethod(PrivateSample parent, String classFullName,
String methodName) throws ClassNotFoundException, NoSuchMethodException,
SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> innerClazz = loader.loadClass(classFullName);
Constructor<?> constructor = innerClazz.getDeclaredConstructor(parent.getClass());
constructor.setAccessible(true);
Object innerObj = constructor.newInstance(parent);
return innerClazz.getDeclaredMethod(methodName).invoke(innerObj);
}
}
Author And Source
この問題について(JUnitでprivate scopeなものをテストする方法), 我々は、より多くの情報をここで見つけました https://qiita.com/harayoshi/items/c7b3878f3d7f1acd28fc著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .