当我将多个自定义匹配器分配给单个方法时,Mockito行为奇怪

san*_*oid 6 java mocking hamcrest matcher mockito

我想为一个方法使用两个自定义匹配器.基本上,如果我传递方法VALUE_A,我希望它返回RESULT_A,如果我将它传递给VALUE_B,我希望它返回RESULT_B.所以这是一段代码摘录:

class IsNonEmpty extends ArgumentMatcher<Get> {
    public boolean matches(Object get) {
        //For some reason, this method is called when I assign the IsEmpty matcher to MockHtable.get()
        //When this happens, the value of the get argument is null, so this method throws an NPE

        return Arrays.equals(((Get) get).getRow(), SERIALIZATION_HELPER.getValidBytes(key)); 
    }
}

class IsEmpty extends ArgumentMatcher<Get> {
    public boolean matches(Object get) {
        return !(Arrays.equals(((Get) get).getRow(), SERIALIZATION_HELPER.getValidBytes(key))); 
    }
}      

[...]

//This line executes just fine
Mockito.when(mockHTable.get(Mockito.argThat(new IsNonEmpty()))).thenReturn(dbResult);

[...]

//This line calls IsNonEmpty.matches() for some reason.  IsNonEmpty.matches() throws an NPE
Mockito.when(mockHTable.get(Mockito.argThat(new IsEmpty()))).thenReturn(emptyResult);
Run Code Online (Sandbox Code Playgroud)

当我将IsEmpty自定义匹配器分配给mockHTable.get()方法时,它调用IsNonEmpty.matches()函数.不知道为什么会这样做.所以我将IsNonEmpty类更改为:

class IsNonEmpty extends ArgumentMatcher<Get> {
    public boolean matches(Object get) {
        //For some reason, this method is called when I assign the IsEmpty matcher.  Weird, no?
        if(get == null) {
            return false;
        }

        return Arrays.equals(((Get) get).getRow(), SERIALIZATION_HELPER.getValidBytes(key)); 
    }
}
Run Code Online (Sandbox Code Playgroud)

然后一切正常!当我将IsEmpty匹配器分配给mockHTable.get()函数时仍然会调用IsNonEmpty.matches(),但我的匹配器确切地工作.

那是什么交易?为什么会这样?我的解决方案是否足以弥补这种奇怪的行为,或者我做错了吗?

Daw*_*ica 11

IsNonEmpty.matches()在第二行存根上调用的原因是Mockito.argThat(new IsEmpty())返回null,然后传递给它mockHTable.get().必须根据之前的存根检查此调用,以查看它是否匹配; 这意味着打电话IsNonEmpty.matches().

我不确定为什么这会让你的测试失败 - 如果没有看到所有代码,很难说清楚.

但是,我会认真推荐使用doReturn...when而不是when...thenReturn每当你不得不多次存根同一个模拟时.如果你这样做,你不会遇到这样的问题.其实,我更喜欢使用doReturn...when优先于when...thenReturn总(类似doThrowdoAnswer),尽管大多数人喜欢when...thenReturn.

使用doReturn...when语法重写一条存根线如下所示.另一个是相似的.

Mockito.doReturn(dbResult).when(mockHTable).get(Mockito.argThat(new IsNonEmpty()));  
Run Code Online (Sandbox Code Playgroud)

最后,代表Mockito开发团队(我是其成员)的请求.如果您认为Mockito中存在错误 - 并且根据您的描述,我认为可能会有 - 请不要

  • 发送消息给Mockito邮件组(mockito@googlegroups.com)或
  • 在Mockito问题列表(http://code.google.com/p/mockito/issues/list)上提出问题.

如果你能真正发布一个完整的例子,而不仅仅是你认为的关键线是什么,这对Mockito团队很有用 - 有时Mockito问题的原因是在一个意想不到的地方.