javaunit-testingjunitpowermockwhite-box

PowerMock: Using Whitebox.invokeMethod(...) properly for a method taking an Object[] as a param


private boolean isEmpty(Object[] array) {
    if (array == null || array.length == 0) 
        return true;
    for (int i = 0; i < array.length; i++) {
    if (array[i] != null) 
        return false;
    }           

    return true;
}

@Test
public void testIsEmpty() {
        //where is an instance of the class whose method isEmpty() I want to test.
    try {
        Object[] arr = null;
        assertTrue((Boolean)(Whitebox.invokeMethod(where, "isEmpty", new Class<?>[]{Object[].class},  arr)));

        arr = new Object[0];
        assertTrue((Boolean)(Whitebox.invokeMethod(where, "isEmpty", new Class<?>[]{Object[].class}, arr)));

        arr = new Object[]{null, null};
        assertTrue((Boolean)(Whitebox.invokeMethod(where, "isEmpty", new Class<?>[]{Object[].class}, arr)));

        arr = new Object[]{1, 2};
        assertFalse((Boolean)(Whitebox.invokeMethod(where, "isEmpty", new Class<?>[]{Object[].class}, arr)));
    } catch (Exception e) {
        fail(e.getMessage());
    }       
}

Problem: java.lang.AssertionError: wrong number of arguments

Research: 1. Initially, I tried: invokeMethod(Object tested, String methodToExecute, Object... arguments)

It failed for the 2nd, 3rd, and 4th invokeMethod(). (Error: method not found with given parameters)

I thought this was potentially due to a problem of PowerMock not being to infer the correct method; hence, I switched to: invokeMethod(Object tested, String methodToExecute, Class[] argumentTypes, Object... arguments)

  1. The parent class has an isEmpty() method that is overrode in the child class with an exact duplicated isEmpty() method. (legacy code) There are no other isEmpty() methods of differing signatures. There are many methods that take parameters, but none others that take an Object[] (e.g. no methods that take an Integer[] as a parameter).

  2. Prior to the second assertTrue statement above, changing to arr = new Object[1] makes that assert statement pass.

Any help is greatly appreciated. Thanks!


Solution

  • I think it should work by casting the argument to Object, in order to make Java take it as a single argument, rather than an array of arguments corresponding to Object...:

    Whitebox.invokeMethod(where, "isEmpty", new Class<?>[]{Object[].class}, (Object) arr);
    

    Test case:

    public static void main(String[] args) {
        foo(new Object[] {"1", "2"}); // prints arg = 1\narg=2
        foo((Object) (new Object[] {"1", "2"})); // prints args = [Ljava.lang.Object;@969cccc
    }
    
    private static void foo(Object... args) {
        for (Object arg : args) {
            System.out.println("arg = " + arg);
        }
    }