Программный вызов Mockito.verify - PullRequest
1 голос
/ 06 августа 2020

У меня есть большая sh кодовая база со многими классами-декораторами, которые обычно делегируют все методы, кроме одного, объекту-делегату, то есть примерно так: , используя Junit 5 @TestFactory, вызывая каждый из методов на WrapperThing, и хотите убедиться, что был вызов обернутого делегата, который является имитацией Mockito.

Вот мой код, поэтому far:

private void testMethodDelegation(final Method method) {
    D delegate = mock(delegateType);
    W wrapper = createWrapper(delegate);

    List<Object> args = new ArrayList<>(method.getParameterTypes().length + 1);
    args.add(wrapper);
    gatherMethodArgs(method, args); // populate args with mocks or default values
    try {
        method.invoke(args.toArray(new Object[0]));
    }catch(Exception e) {
        // this is fine, we're just testing the delegation
    }

    // now comes the verify part
    List<Object> mockArgs = new ArrayList<>();
    try {
        mockArgs.add(verify(delegate));
        mockArgs.addAll(nCopies(args.size()-1, any()));
        method.invoke(mockArgs.toArray(new Object[0]));
    }catch (Exception e) {
        throw new IllegalStateException(e);
    }

}

Когда я запускаю это, я получаю сообщение об ошибке:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here:

-> at some.packagename.AbstractDelegateTest.testMethodDelegation(AbstractDelegateTest.java:81)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

Я делаю что-то не так, или невозможно проверить вызов метода, если вы не Не знаете точный метод?

1 Ответ

1 голос
/ 06 августа 2020

Проблема в том, что я неправильно вызвал method.invoke (). Я думал, что это формат method.invoke([target, arg1, ... argn]), но на самом деле это method.invoke(target, [arg1, ... argn]). Это был долгий день, плохо.

Этот код работает:

private void testMethodDelegation(final Method method) {
    D delegate = mock(delegateType);
    W wrapper = createWrapper(delegate);

    List<Object> args = new ArrayList<>(method.getParameterTypes().length);
    gatherMethodArgs(method, args); // populate args with mocks or default values
    try {
        method.invoke(wrapper, args.toArray(new Object[0]));
    } catch (Exception e) {
        // this is fine, we're just testing the delegation
        throw new IllegalStateException(e);
    }
    callVerify(method, delegate);
}

private void callVerify(final Method method, final D delegate) {
    // now comes the verify part
    List<Object> mockArgs = new ArrayList<>(method.getParameterTypes().length);
    try {
        D verifyDelegate = verify(delegate);
        gatherVerifyArgs(method, mockArgs);
        method.invoke(verifyDelegate, mockArgs.toArray(new Object[0]));
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}

private void gatherVerifyArgs(final Method method, final List<Object> args) {
    for (Class<?> parameterType : method.getParameterTypes()) {
        if (int.class == parameterType) {
            args.add(anyInt());
        } else if (boolean.class == parameterType) {
            args.add(anyBoolean());
        } else if (long.class == parameterType) {
            args.add(anyLong());
        } else if (double.class == parameterType) {
            args.add(anyDouble());
        } else if (float.class == parameterType) {
            args.add(anyFloat());
        } else if (String.class == parameterType) {
            args.add(anyString());
        } else {
            args.add(any());
        }
    }
}

private void gatherMethodArgs(final Method method, final List<Object> args) {

    int i = 0;
    for (Class<?> type : method.getParameterTypes()) {
        try {
            if (type == String.class) {
                args.add("");
            } else if (type.isArray()) {
                args.add(Array.newInstance(type.getComponentType(), 0));
            } else if (Primitives.allPrimitiveTypes().contains(type)) {
                args.add(Defaults.defaultValue(type));
            } else if (Primitives.allWrapperTypes().contains(type)) {
                args.add(Defaults.defaultValue(Primitives.unwrap(type)));
            } else if (type == List.class) {
                args.add(ImmutableList.of());
            } else if (type == Set.class) {
                args.add(ImmutableSet.of());
            } else if (type == Map.class) {
                args.add(ImmutableMap.of());
            } else if (type.getName().startsWith("java.util.")) {
                args.add(type.newInstance());
            } else {
                args.add(mock(type));
            }
        } catch (Exception e) {
            throw new IllegalStateException(
                String.format("Error mocking parameter %d (%s) of method %s", i,
                              method.getGenericParameterTypes()[i], method), e);
        }
        i++;
    }
}
...