Java 以编程方式调用Mockito.verify

Java 以编程方式调用Mockito.verify,java,mockito,Java,Mockito,我有一个较大的代码库,包含许多装饰器类,它们通常将除一个方法外的所有方法委托给一个委托对象,例如: class WrapperThing implements Thing{ private final Thing delegate; WrapperThing(Thing thing){this.delegate=thing;} public boolean method1(){ return delegate.method1(); } public String met

我有一个较大的代码库,包含许多装饰器类,它们通常将除一个方法外的所有方法委托给一个委托对象,例如:

class WrapperThing implements Thing{
   private final Thing delegate;
   WrapperThing(Thing thing){this.delegate=thing;}

   public boolean method1(){ return delegate.method1(); }
   public String method2(int arg1, boolean arg2){ return delegate.method2(arg1, arg2); }
   // lots more methods here, all delegating to delegate
}
现在,我正在使用Junit 5
@TestFactory
为这些包装创建单元测试,调用
WrapperThing
上的每个方法,并希望验证包装委托上是否有调用,这是一个Mockito mock

以下是我目前的代码:

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

}

我是否做错了什么,或者如果您不知道确切的方法,是否无法验证方法调用?

问题是我调用的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++;
    }
}
private void testMethodDelegation(最终方法){
D delegate=mock(delegateType);
W wrapper=createWrapper(委托);
List args=new ArrayList(method.getParameterTypes().length);
gatherMethodArgs(method,args);//用mock或默认值填充args
试一试{
invoke(包装器,args.toArray(新对象[0]);
}捕获(例外e){
//这很好,我们只是在测试代表团
抛出新的非法状态异常(e);
}
callVerify(方法、委托);
}
私有void callVerify(final方法,final D委托){
//现在是验证部分
List mockArgs=newarraylist(method.getParameterTypes().length);
试一试{
D验证委托=验证(委托);
gatherVerifyArgs(方法,mockArgs);
invoke(verifyDelegate,mockArgs.toArray(新对象[0]);
}捕获(例外e){
抛出新的非法状态异常(e);
}
}
私有void gatherVerifyArgs(最终方法,最终列表args){
对于(类parameterType:method.getParameterTypes()){
if(int.class==参数类型){
args.add(anyInt());
}else if(boolean.class==参数类型){
args.add(anyBoolean());
}else if(long.class==参数类型){
args.add(anyLong());
}else if(double.class==参数类型){
args.add(anyDouble());
}else if(float.class==参数类型){
args.add(anyFloat());
}else if(String.class==参数类型){
add(anyString());
}否则{
args.add(any());
}
}
}
私有方法参数(最终方法、最终列表参数){
int i=0;
for(类类型:method.getParameterTypes()){
试一试{
if(type==String.class){
参数。添加(“”);
}else if(type.isArray()){
add(Array.newInstance(type.getComponentType(),0));
}else if(Primitives.allPrimitiveTypes().contains(type)){
add(Defaults.defaultValue(type));
}else if(Primitives.allWrapperTypes().contains(type)){
add(Defaults.defaultValue(Primitives.unwrap(type));
}else if(type==List.class){
add(ImmutableList.of());
}else if(type==Set.class){
add(ImmutableSet.of());
}else if(type==Map.class){
add(ImmutableMap.of());
}else if(type.getName().startsWith(“java.util”)){
args.add(type.newInstance());
}否则{
参数add(模拟(类型));
}
}捕获(例外e){
抛出新的非法状态异常(
String.format(“模拟方法%s的参数%d(%s)时出错”,i,
getGenericParameterTypes()[i],方法),e);
}
i++;
}
}

作为参数传入的是什么方法?看起来您只想将包装器或委托作为第一个参数传递。如果是这样的话,你为什么需要验证?哦,等等。您是否正在测试您的方法是否为委托方法?基本上,“当调用包装器中的方法A时,将调用委托中的方法A”。
method.invoke(method,…)
没有意义。第一个参数是调用该方法的对象。它应该是
method.invoke(wrapper,…)
method.invoke(delegate,…)
@georgeyep,可能就是这样。漫长的一天,sorry@George修正了这个错误,但不幸的是它没有解决我的问题,只是产生了一个新的错误
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++;
    }
}