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

时间:2012-04-26 22:45:23

标签: java mocking mockito matcher hamcrest

我想在单个方法中使用两个自定义匹配器。基本上,如果我传递方法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);

当我将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)); 
    }
}

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

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

1 个答案:

答案 0 :(得分: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()));  

最后,代表Mockito开发团队(我是其中的一员)的请求。如果您认为Mockito中存在错误 - 并且根据您的描述,我认为可能存在 - 请使用

  • 向Mockito邮件群发送邮件(mockito@googlegroups.com)或
  • 在Mockito问题列表中提出问题(http://code.google.com/p/mockito/issues/list)。

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