私が尋ねた質問への回答で、特定の (無関係な) 問題を解決するには、メイン クラス (C) をテストするように設計されたクラス (test_C) を C の子クラスにすることを勧められました。
public class test_C extends C {
これは Java 開発の一般的なパターンですか?
すべてのテスト クラスにこのパターンを使用しない理由はありますか (テスト クラスとテスト済みクラスの間に常に 1 対 1 のマッピングがあると仮定します)。
すべてのテスト クラスにこのパターンを使用しない理由はありますか (テスト クラスとテスト済みクラスの間に常に 1 対 1 のマッピングがあると仮定します)。
テスト対象のクラスは final になる可能性があり、どのクラスもそれをサブクラス化できなくなります。
public final class C { ... }
サブクラスのテストが実現可能であれば、テスト対象のクラスの動作を意図的ではなく意図的に変更する可能性があります。
1)まあ、一般的なパターンかどうかはわかりませんが、私はすでにそれを使用し、いくつかの欠点を発見しました。
2) そうしない理由は非常に単純です。プライベート アクセサーと最終クラスまたはメソッドを使用することをお勧めします。後者を本当に適用すると、クラスまたはメソッドをテストするために多くの重複クラスを作成することになります。また、チームの誰かが本番環境でダミーの拡張クラスを使用しないようにするにはどうすればよいでしょうか?
この問題に対する私の解決策は、リフレクションを使用してプライベート コンストラクターとメソッドにアクセスすることでした。なんとなくややこしいですが、あとは繰り返しです。現在、すべてのテストにユーティリティ リフレクション クラスを使用しています。
以下は私のリフレクションユーティリティクラスです:
import static org.junit.Assert.fail;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* The Class JunitReflectionUtils.
*/
public final class JunitReflectionUtils {
/**
* Instantiates a new junit reflection utils.
*/
private JunitReflectionUtils() {
}
/**
* Gets the method.
*
* @param givenClass_ the given class_
* @param methodName_ the method name
* @param failIfException_ if true, the method will fail
* @param parametersClass_ the parameters
* @return the method
*/
public static Method getMethod(Class<?> givenClass_, String methodName_, boolean failIfException_, Class<?> ... parametersClass_) {
Method _method = null;
try {
_method = givenClass_.getDeclaredMethod(methodName_, parametersClass_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("A method called \"" + methodName_ + "\" could not be retrieved: " + _exception.getMessage());
} else {
return null;
}
}
_method.setAccessible(true);
return _method;
}
/**
* Gets the field.
*
* @param givenClass_ the given class
* @param fieldName_ the field name
* @param failIfException_ if true then the method will fail if an exception is thrown
* @return the field
*/
public static Field getField(Class<?> givenClass_, String fieldName_, boolean failIfException_) {
Field _field = null;
try {
_field = givenClass_.getDeclaredField(fieldName_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("A field called \"" + fieldName_ + "\" could not be retrieved: " + _exception.getMessage());
} else {
return null;
}
}
_field.setAccessible(true);
return _field;
}
/**
* assign value to a field.
*
* @param field_ the given field
* @param parentObject_ the parent containing the field
* @param failIfException_ if true then the method will fail if an exception is thrown
* @param value_ the value to assign to the field
* @return the field
*/
public static boolean assignValueToField(Field field_, Object parentObject_, boolean failIfException_, Object value_) {
try {
field_.set(parentObject_, value_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("An exception has occured while setting a value to a field: " + _exception.getMessage());
}
return false;
}
return true;
}
/**
* Gets the field value from a given object.
*
* @param object_ the object
* @param fieldName_ the field name
* @param failIfException_ if true, this method will fail if an exception is thrown
* @return the field value from object
*/
public static Object getFieldValueFromObject(Object object_, String fieldName_, boolean failIfException_) {
Field _givenField = getField(object_.getClass(), fieldName_, failIfException_);
Object _returnedValue = null;
if (_givenField == null) {
return null;
} else {
try {
_returnedValue = _givenField.get(object_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("An exception has occured while retrieving a value from a field : " + _exception.getMessage());
} else {
return null;
}
}
}
return _returnedValue;
}
/**
* Gets the constructor.
*
* @param givenClass_ the given class
* @param failIfException_ if true, a fail statement will be issued when an exception is thrown
* @param parametersClasses_ the parameters classes_
* @return the constructor
*/
public static Constructor<?> getConstructor(Class<?> givenClass_, boolean failIfException_, Class<?> ... parametersClasses_) {
Constructor<?> _constructor = null;
try {
_constructor = givenClass_.getDeclaredConstructor(parametersClasses_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("The constructor from the class \"" + givenClass_.getName() + "\" could not be retrieved");
} else {
return null;
}
}
_constructor.setAccessible(true);
return _constructor;
}
/**
* Instantiante an object.
*
* @param givenClass_ the given class
* @param failIfException_ if true then a fail statement will be issued if an exception is thrown
* @param parametersClasses_ the parameters classes
* @param parameters_ the parameters
* @return the object
*/
public static Object instantianteAnObject(Class<?> givenClass_, boolean failIfException_, Class<?> [] parametersClasses_, Object... parameters_) {
Constructor<?> _constructor = getConstructor(givenClass_, failIfException_, parametersClasses_);
Object _returnedObject = null;
if (_constructor != null) {
try {
_returnedObject = _constructor.newInstance(parameters_);
} catch (Exception _exception) {
_exception.printStackTrace();
if (failIfException_) {
fail("An instance of " + givenClass_.getName() + " could not be created : " + _exception.getMessage());
} else {
return null;
}
}
}
return _returnedObject;
}
}