dimanche 27 décembre 2020

Mockito: Attach Answer to every method of arbitrary Object instance

I have the following situation:

I want to attach an Answer to every method call of a specific class instance. So for example with the class

public class Example {
    public int example1() { /* */ }
    public int example2(Object a) { /* */ }
    public int example3(Object a, Integer b) { /* */ }
    public int example4(int a) { /* */ }
}

I want to do the following

public Example attachToExample(Example ex) {
    Example spy = Mockito.spy(ex);
    Answer<Object> answer = /* */;
    doAnswer(answer).when(spy).example1();
    doAnswer(answer).when(spy).example2(any());
    doAnswer(answer).when(spy).example3(any(), any());
    doAnswer(answer).when(spy).example4(anyInt());
    return spy;
}

This works but what I would like to do is generalize this to not just Example instances but arbitrary Objects.

So what I would like to do is

public Object attachToExample(Object o) {
    Object spy = Mockito.spy(o);
    Answer<Object> answer = /* */;
    for(Method m : o.getClass().getMethods()) {
        /* skipping methods that cannot be mocked (equals/hashCode/final/..) */

        doAnswer(answer).when(spy)./* Method m with according arguments */;
    }
    return spy;
}

What I would need to do for that is construct argument matchers any/anyInt/.. depending on the amount of parameters of each method and their types (primitive/non primitive). Ideally I would create a list of arguments like this:

Class<?>[] params = m.getParameterTypes();
ArrayList<Object> args = new ArrayList<>();
for (Class<?> param : params) {
    if ("int".equals(param.toString())) {
        args.add(ArgumentMatchers.anyInt());
    } else { // Cases for other primitive types left out.
        args.add(ArgumentMatchers.any()); // Found non primitive. We can use 'any()'
    }
}
            
try {
    doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
            .invoke(spy, args.toArray());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
    e.printStackTrace();
}

This does not work as using argument matchers outside of stubbing is not supported but I hope that this makes clear what I want to do.

Is there any way to make this work or is there a different way of archiving what I want to do?





Aucun commentaire:

Enregistrer un commentaire