Mockito 不理解在反射方法上调用 method.invoke()
Mockito doesn't understand calling method.invoke() on reflected Method
这个问题非常复杂,这种行为对我来说毫无意义。
我有这个 class:
public class TestMethodsProvider extends AnnotatedCommandExecutor<JavaPlugin> {
public TestMethodsProvider(final CommandSender sender, final JavaPlugin plugin) {
super(sender, plugin);
}
@Argument
public void testMethodWithParam(@Mapper("testWorldMapper") final World world) {
}
@ArgumentFallback("testWorldMapper")
public void testMethodWithParamArgumentFallback(final String world) {
}
}
基本行为如下:
- 引擎反射性地调用
testMethodWithParam
。
- 该方法具有复杂的参数,因此引擎尝试从原始字符串创建
World
对象(由于 @Mapper("testWorldMapper")
注释)。
- 映射失败(创建
null
),因此应调用回退方法(如果存在)。
- 引擎搜索
@ArgumentFallback("testWorldMapper")
的 class(提供的文本必须与 @Mapper("testWorldMapper")
中的相同)
- 如果找到该方法,将使用即将成为
World
且失败的文本调用它。
第 1-2 点现在并不重要,它们仅用于理解行为。
我有一个 class 设计来完成第 3-5 点:
public class FallbackInvoker<E extends JavaPlugin> {
@NotNull
public Object invokeFallback(@Nullable final Mapper mapper,
@NotNull final String text,
@NotNull final Class<?> targetClass,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Optional.ofNullable(mapper)
.map(x -> getArgumentFallbackMethods(x.value(), executor))
.or(() -> Optional.of(getTypeFallbackMethods(targetClass, executor)))
.stream()
.flatMap(Collection::stream)
.map(method -> invokeMethod(method, executor, text))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@NotNull
private List<Method> getArgumentFallbackMethods(@NotNull final String argument,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Arrays.stream(executor.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(ArgumentFallback.class))
.filter(method -> Arrays.asList(method.getAnnotation(ArgumentFallback.class).value())
.contains(argument))
.filter(method -> method.getParameterCount() == 1)
.sorted((o1, o2) -> o2.getAnnotation(ArgumentFallback.class).priority().getSlot()
- o1.getAnnotation(ArgumentFallback.class).priority().getSlot())
.collect(Collectors.toList());
}
@NotNull
private List<Method> getTypeFallbackMethods(@NotNull final Class<?> type,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Arrays.stream(executor.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(TypeFallback.class))
.filter(method -> Arrays.asList(method.getAnnotation(TypeFallback.class).value())
.contains(type))
.filter(method -> method.getParameterCount() == 1)
.sorted((o1, o2) -> o2.getAnnotation(TypeFallback.class).priority().getSlot()
- o1.getAnnotation(TypeFallback.class).priority().getSlot())
.collect(Collectors.toList());
}
@SneakyThrows
private Object invokeMethod(@NotNull final Method method,
@NotNull final AnnotatedCommandExecutor<E> executor,
@NotNull final String text) {
return method.invoke(executor, text); // THIS LINE IS IMPORTANT
}
}
测试看起来像这样:
@Test
void theTest() throws ReflectiveOperationException {
final JavaPlugin plugin = mock(JavaPlugin.class);
final CommandSender sender = mock(CommandSender.class);
final IFallbackInvoker<JavaPlugin> invoker = new FallbackInvoker<>();
final Class<? extends TestMethodsProvider> providerClass = TestMethodsProvider.class;
final Method fallbackMethod = spy(providerClass.getDeclaredMethod("testMethodWithParamArgumentFallback",
String.class));
final Method method = providerClass.getDeclaredMethod("testMethodWithParam", World.class);
final TestMethodsProvider testMethodsProvider = (TestMethodsProvider) providerClass.getConstructors()[0]
.newInstance(sender, plugin);
final Mapper mapper = method.getParameters()[0].getAnnotation(Mapper.class);
final Object result = invoker.invokeFallback(mapper, "test", World.class, testMethodsProvider);
assertEquals(new ArrayList<>(), result);
verify(fallbackMethod, times(1)).invoke(any(), any());
}
一切看起来都与事实完全不同......它失败了。消息是:
Wanted but not invoked:
method.invoke(<any>, <any>);
-> at java.base/java.lang.reflect.Method.invoke(Method.java:556)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
method.invoke(<any>, <any>);
-> at java.base/java.lang.reflect.Method.invoke(Method.java:556)
Actually, there were zero interactions with this mock.
at java.base/java.lang.reflect.Method.invoke(Method.java:556)
at eu.andret.arguments.mapper.FallbackInvokerTest.dupa(FallbackInvokerTest.java:54)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod[=14=](ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke[=14=](ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access[=14=]0(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
失败意味着没有调用上面指出的行。但是当我在那里执行 System.out.println(method);
时,它会准确地打印出我想要调用的方法。我还尝试调试它并且调试器停在那里,因此应该调用该方法。为什么不是?
我想补充一点我有一个类似的测试(用于测试正确的映射)效果很好:
@Test
void invokeFallbackMethodWith() throws ReflectiveOperationException {
// given
final JavaPlugin plugin = mock(JavaPlugin.class);
final CommandSender sender = mock(CommandSender.class);
abstract class LocalFunction implements Function<String, World> {
}
abstract class LocalFallbackInvoker extends FallbackInvoker<JavaPlugin> {
}
final Function<String, World> getWorld = mock(LocalFunction.class);
final MappingConfig mappingConfig = new MappingConfig();
mappingConfig.add("testWorldMapper", new MappingSet<>(World.class, getWorld, TypeFallback.ALWAYS));
final IFallbackInvoker<JavaPlugin> fallbackInvoker = mock(LocalFallbackInvoker.class);
final IMethodInvoker<JavaPlugin> invoker = new MethodInvoker<>(plugin, mappingConfig, fallbackInvoker);
final Class<? extends AnnotatedCommandExecutor<JavaPlugin>> provider = TestMethodsProvider.class;
final Method methodWorld = spy(provider.getDeclaredMethod("testMethodWithParam", World.class));
final Mapper mapper = methodWorld.getParameters()[0].getAnnotation(Mapper.class);
final TestMethodsProvider o = (TestMethodsProvider) provider.getConstructors()[0].newInstance(sender, plugin);
// when
invoker.invokeMethod(methodWorld, new String[]{"testMethod", "test"}, sender, provider);
// then
verify(methodWorld, times(0)).invoke(any());
verify(fallbackInvoker, times(1)).invokeFallback(mapper, "test", World.class, o);
}
然后我现在完全不明白。为什么一个测试通过而另一个没有通过?怎样做才能使测试通过?手动测试时,一切正常,只有测试有一些我没有看到的问题。
当使用 Mockito 的 verify()
时,所有调用都必须对由 mock()
或 spy()
创建的实例进行,否则它们将无法被 Mockito 记录。
在您的第一个测试中,您永远不会将创建的间谍传递给 invokeFallback()
函数,因此 Mockito 不知道您正在进行的调用。
在您的第二个测试(工作测试)中,您正在调用 spy()
返回的方法,这就是它起作用的原因。
这个问题非常复杂,这种行为对我来说毫无意义。
我有这个 class:
public class TestMethodsProvider extends AnnotatedCommandExecutor<JavaPlugin> {
public TestMethodsProvider(final CommandSender sender, final JavaPlugin plugin) {
super(sender, plugin);
}
@Argument
public void testMethodWithParam(@Mapper("testWorldMapper") final World world) {
}
@ArgumentFallback("testWorldMapper")
public void testMethodWithParamArgumentFallback(final String world) {
}
}
基本行为如下:
- 引擎反射性地调用
testMethodWithParam
。 - 该方法具有复杂的参数,因此引擎尝试从原始字符串创建
World
对象(由于@Mapper("testWorldMapper")
注释)。 - 映射失败(创建
null
),因此应调用回退方法(如果存在)。 - 引擎搜索
@ArgumentFallback("testWorldMapper")
的 class(提供的文本必须与@Mapper("testWorldMapper")
中的相同) - 如果找到该方法,将使用即将成为
World
且失败的文本调用它。
第 1-2 点现在并不重要,它们仅用于理解行为。
我有一个 class 设计来完成第 3-5 点:
public class FallbackInvoker<E extends JavaPlugin> {
@NotNull
public Object invokeFallback(@Nullable final Mapper mapper,
@NotNull final String text,
@NotNull final Class<?> targetClass,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Optional.ofNullable(mapper)
.map(x -> getArgumentFallbackMethods(x.value(), executor))
.or(() -> Optional.of(getTypeFallbackMethods(targetClass, executor)))
.stream()
.flatMap(Collection::stream)
.map(method -> invokeMethod(method, executor, text))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@NotNull
private List<Method> getArgumentFallbackMethods(@NotNull final String argument,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Arrays.stream(executor.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(ArgumentFallback.class))
.filter(method -> Arrays.asList(method.getAnnotation(ArgumentFallback.class).value())
.contains(argument))
.filter(method -> method.getParameterCount() == 1)
.sorted((o1, o2) -> o2.getAnnotation(ArgumentFallback.class).priority().getSlot()
- o1.getAnnotation(ArgumentFallback.class).priority().getSlot())
.collect(Collectors.toList());
}
@NotNull
private List<Method> getTypeFallbackMethods(@NotNull final Class<?> type,
@NotNull final AnnotatedCommandExecutor<E> executor) {
return Arrays.stream(executor.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(TypeFallback.class))
.filter(method -> Arrays.asList(method.getAnnotation(TypeFallback.class).value())
.contains(type))
.filter(method -> method.getParameterCount() == 1)
.sorted((o1, o2) -> o2.getAnnotation(TypeFallback.class).priority().getSlot()
- o1.getAnnotation(TypeFallback.class).priority().getSlot())
.collect(Collectors.toList());
}
@SneakyThrows
private Object invokeMethod(@NotNull final Method method,
@NotNull final AnnotatedCommandExecutor<E> executor,
@NotNull final String text) {
return method.invoke(executor, text); // THIS LINE IS IMPORTANT
}
}
测试看起来像这样:
@Test
void theTest() throws ReflectiveOperationException {
final JavaPlugin plugin = mock(JavaPlugin.class);
final CommandSender sender = mock(CommandSender.class);
final IFallbackInvoker<JavaPlugin> invoker = new FallbackInvoker<>();
final Class<? extends TestMethodsProvider> providerClass = TestMethodsProvider.class;
final Method fallbackMethod = spy(providerClass.getDeclaredMethod("testMethodWithParamArgumentFallback",
String.class));
final Method method = providerClass.getDeclaredMethod("testMethodWithParam", World.class);
final TestMethodsProvider testMethodsProvider = (TestMethodsProvider) providerClass.getConstructors()[0]
.newInstance(sender, plugin);
final Mapper mapper = method.getParameters()[0].getAnnotation(Mapper.class);
final Object result = invoker.invokeFallback(mapper, "test", World.class, testMethodsProvider);
assertEquals(new ArrayList<>(), result);
verify(fallbackMethod, times(1)).invoke(any(), any());
}
一切看起来都与事实完全不同......它失败了。消息是:
Wanted but not invoked:
method.invoke(<any>, <any>);
-> at java.base/java.lang.reflect.Method.invoke(Method.java:556)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
method.invoke(<any>, <any>);
-> at java.base/java.lang.reflect.Method.invoke(Method.java:556)
Actually, there were zero interactions with this mock.
at java.base/java.lang.reflect.Method.invoke(Method.java:556)
at eu.andret.arguments.mapper.FallbackInvokerTest.dupa(FallbackInvokerTest.java:54)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod[=14=](ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke[=14=](ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access[=14=]0(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
失败意味着没有调用上面指出的行。但是当我在那里执行 System.out.println(method);
时,它会准确地打印出我想要调用的方法。我还尝试调试它并且调试器停在那里,因此应该调用该方法。为什么不是?
我想补充一点我有一个类似的测试(用于测试正确的映射)效果很好:
@Test
void invokeFallbackMethodWith() throws ReflectiveOperationException {
// given
final JavaPlugin plugin = mock(JavaPlugin.class);
final CommandSender sender = mock(CommandSender.class);
abstract class LocalFunction implements Function<String, World> {
}
abstract class LocalFallbackInvoker extends FallbackInvoker<JavaPlugin> {
}
final Function<String, World> getWorld = mock(LocalFunction.class);
final MappingConfig mappingConfig = new MappingConfig();
mappingConfig.add("testWorldMapper", new MappingSet<>(World.class, getWorld, TypeFallback.ALWAYS));
final IFallbackInvoker<JavaPlugin> fallbackInvoker = mock(LocalFallbackInvoker.class);
final IMethodInvoker<JavaPlugin> invoker = new MethodInvoker<>(plugin, mappingConfig, fallbackInvoker);
final Class<? extends AnnotatedCommandExecutor<JavaPlugin>> provider = TestMethodsProvider.class;
final Method methodWorld = spy(provider.getDeclaredMethod("testMethodWithParam", World.class));
final Mapper mapper = methodWorld.getParameters()[0].getAnnotation(Mapper.class);
final TestMethodsProvider o = (TestMethodsProvider) provider.getConstructors()[0].newInstance(sender, plugin);
// when
invoker.invokeMethod(methodWorld, new String[]{"testMethod", "test"}, sender, provider);
// then
verify(methodWorld, times(0)).invoke(any());
verify(fallbackInvoker, times(1)).invokeFallback(mapper, "test", World.class, o);
}
然后我现在完全不明白。为什么一个测试通过而另一个没有通过?怎样做才能使测试通过?手动测试时,一切正常,只有测试有一些我没有看到的问题。
当使用 Mockito 的 verify()
时,所有调用都必须对由 mock()
或 spy()
创建的实例进行,否则它们将无法被 Mockito 记录。
在您的第一个测试中,您永远不会将创建的间谍传递给 invokeFallback()
函数,因此 Mockito 不知道您正在进行的调用。
在您的第二个测试(工作测试)中,您正在调用 spy()
返回的方法,这就是它起作用的原因。