Thursday, March 17, 2016

Using Java's Reflection for Testing

Repeatedly writing for loops for testing is not fun.

We can use Java reflection API (java.lang.reflect package) to maximize code reuse and help testing.

private final static String SUCCESS = "Congrats! All tests passed.";

public static <T, R> void assertEqual(String className, String methodName,
  T[] inputs, R[] expected) {
  // make sure they have same length
  validateLengths(inputs, expected);
  
  try {
    // use reflection to get type of class indicated by "className"
    Class<?> c = Class.forName(className);
    Class<T> inputType = (Class<T>) inputs[0].getClass();
    Method m = c.getMethod(methodName, inputType);

    // static methods will ignore this instance
    Object o = c.newInstance();

    for (int i = 0; i < inputs.length; i++) {
      R e = expected[i];
      R output = (R) m.invoke(o, inputs[i]);

      // has to test deep equal for array type
      if (e.getClass().isArray()) {
        int n = Array.getLength(e);
        for (int j = 0; j < n; j++) {
          if (!Array.get(e, j).equals(Array.get(output, j))) {
            System.out.println("test failed for "
              + Arrays.asList(inputs[i]) + " expected "
              + Arrays.asList(e) + ", output "
              + Arrays.asList(output));
            System.exit(-1);
          }
        }
      } else if (!e.equals(output)) {
        System.out.println("test:\n " + inputs[i] + "failed, "
          + " expected " + expected + ", output " + output);
        System.exit(-1);
      }

    }
    
    // all tests passed
    System.out.println(SUCCESS);
  
  } catch (ClassNotFoundException | IllegalAccessException
    | IllegalArgumentException | InvocationTargetException
    | NoSuchMethodException | SecurityException
    | InstantiationException e) {
    //handle your exceptions here
    e.printStackTrace();
  }
}




To use the method, call:

assertEqual("my.pkg.className","methodName",inputArray,
         expectedResultsArray);



Don't forget to include the package name.

No comments: