Java Mockito:验证具有类型兼容参数的重载方法

Java Mockito:验证具有类型兼容参数的重载方法,java,eclipse,mockito,overload-resolution,ecj,Java,Eclipse,Mockito,Overload Resolution,Ecj,假设您希望使用包含以下方法签名的Mockito模拟接口: public void doThis(Object o); public void doThis(Object... o) 我需要验证这(对象o)(而不是另一个方法)是否只调用了一次 首先,我认为下面这句话可以达到目的: verify(mock, times(1)).doThis(anyObject()); 但是,由于这在Windows上似乎有效,因此在Linux上不起作用,因为在此环境中,需要调用另一个方法来调用此方法。 这是因为

假设您希望使用包含以下方法签名的
Mockito
模拟接口:

public void doThis(Object o);

public void doThis(Object... o)
我需要验证
这(对象o)
(而不是另一个方法)是否只调用了一次

首先,我认为下面这句话可以达到目的:

verify(mock, times(1)).doThis(anyObject());
但是,由于这在Windows上似乎有效,因此在Linux上不起作用,因为在此环境中,需要调用另一个
方法来调用此方法。
这是因为
anyObject()
参数似乎与两个方法签名都匹配,并且以或多或少不可预测的方式选择了一个

我如何强制执行Mockito始终选择
doThis(Object o)
进行验证?

这不是Mockito的问题。

在进一步调查中。因此,windows和linux之间的类文件基本上是不同的,这导致了不同的mockito行为

不鼓励使用该接口(请参阅《有效Java》,第二版,第42项)。 我将其更改为与以下内容相匹配:

public void doThis(Object o);

public void doThis(Object firstObj, Object... others)
通过此更改,将始终选择预期(第一)方法

还剩下一件事:
为什么windows上的java编译器(eclipse编译器)产生的输出与Linux上的Oracle JDK javac不同


这可能是ECJ中的一个错误,因为我认为java语言规范在这里是非常严格的。

我同意另一个答案中的大部分,只是有一部分还没有得到回答:为什么编译器之间存在差异

仔细看,这不是ecj和javac之间的区别,而是JLS的不同版本之间的区别:

  • 在compliance 1.7或更低版本下编译时,两个编译器都选择第一个(单参数)方法
  • 在compliance 1.8下编译时,两个编译器都选择第二个(varargs)方法
让我们看看产生的字节码:

     7: invokestatic  #8                  // Method anyObject:()Ljava/lang/Object;
    10: checkcast     #9                  // class "[Ljava/lang/Object;"
    13: invokevirtual #10                 // Method doThis:([Ljava/lang/Object;)V
(两个编译器也同意这些字节)

这就是说:Java8中的推理功能变得更加强大,现在能够推断
anyObject()
Object[]
的类型参数。这可以通过
checkcast
指令看到,该指令被翻译回源代码,读取:
(Object[])anyObject()
。这意味着也可以在不使用varargs magic的情况下调用
doThis(Object…
,但只需传递一个
Object[]
类型的参数即可

现在这两种方法都适用于同一类别(“通过固定算术调用适用”),搜索适用方法中最具体的方法将选择第二种方法

相比之下,Java7只允许以变量arity调用的形式调用第二个方法,但如果找到了固定的arity匹配项,就不会尝试这样做

上述内容还说明了如何使计划对JLS中的变化具有鲁棒性:

verify(mock, times(1)).doThis(Matchers.<Object>anyObject());
verify(mock,times(1)).doThis(Matchers.anyObject());

这将告诉所有版本的编译器都选择第一种方法,因为现在它总是会看到<代码> DOTHESE()/<代码>作为<代码>对象< /代码>——如果你真的无法避免这种不健康的超载,那就是:

听起来有点像你定义的JavaC无bug。