2

In an answer to a question I asked, I was advised to solve a particular (irrelevant) problem by making a class (test_C) designed to test the main class (C) be a child class of C:

public class test_C extends C {
  1. Is this a common pattern in Java development?

  2. Are there any reasons NOT to use this pattern for all test classes (assume that we always have 1-1 mapping between test class and tested class)?

4

2 回答 2

3

Are there any reasons NOT to use this pattern for all test classes (assume that we always have 1-1 mapping between test class and tested class)?

The class being tested can be final, preventing any class from subclassing it.

 public final class C { ... }

If a testing subclass is feasible, it could alter the behavior of the class being tested -- unintentionally as well as intentionally.

于 2013-06-27T04:00:33.420 回答
1

1) Well, I do not know if it is a general pattern but i already used it and found some drawbacks.

2) the reasons to not do it are fairy simple. It is recommended to use private accessor and final class or method. If you really apply the later, you will end up with producing many duplicate classes to test a class or a method. Also, How can you make sure somebody in your team will not end up using the dummy extended class in production?

My solution to this problem was to use reflection to access private constructors and methods. It is somehow a bit tricky but afterwards it is a repetition. I am using now my utility reflection class for all my tests.

Below is my reflection utility class:

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;
    }


}
于 2013-06-27T03:46:58.073 回答