2016-03-02 60 views
0

错误的Mockito我有一个Java类:定制匹配

import java.util.List; 
    public class Service 
    { 
    public List<Object> someMethod(final List<Object> list) { 
     return null; 
    } 
    } 

而且在那里我已经定义了自定义匹配一个斯波克测试:

进口org.mockito.ArgumentMatcher 进口spock.lang。规格

import static org.mockito.Mockito.* 

    class InstantBookingInitialDecisionTest extends Specification { 

     def mock = mock(Service.class) 

     def setup() { 
      when(mock.someMethod(argThat(hasSize(2)))).thenReturn([]) 
      when(mock.someMethod(argThat(hasSize(3)))).thenReturn([]) 
     } 

     def 'Minimum hunger requirements do not apply to schedulable pros'() { 
      when: 
      'something' 
      then: 
      'something else' 
     } 

     // Damn, there's a Hamcrest matcher for this, but it's not in the jar that the javadocs say it is, so making my own 
     static def hasSize(size) { 
      new ArgumentMatcher<List>() { 
       @Override 
       boolean matches(Object o) { 
        List list = (List) o 
        return list.size() == size 
       } 
      } 
     } 
    } 

原样,这个测试使我有以下错误:

java.lang.NullPointerException: Cannot invoke method size() on null object 

如果我删除when中的任何一个,我就不会有任何错误。所以它不喜欢的是测试的残段,以及我使用了自定义匹配器两次的事实。

注:

  1. 我试图声明为每个列表大小一个单独的类,如mockito anyList of a given size和文档的Mockito。我犯了同样的错误。
  2. 我试过使用看起来像这样的Hamcrest匹配器,但尽管1.3 Javadoc列出了一个Matchers.hasSize()方法,但我的导入的1.3 jar不包含匹配器。 (但即使我得到了依赖解决,我仍然想要了解问题。)

请不要问为什么我使用Mockito而不是Spock Mocks - 我有我的理由。 ;)

谢谢

+0

如果matches()检查null并为null参数返回false(因为它应该这样做,IMO)会发生什么 –

+0

我正在使用Mockito文档(基本上)的示例,它不检查null。 – orbfish

回答

0

的根本原因是,您的自定义匹配可以抛出异常,这不符合匹配器的总承包。由于Mockito的内部原因,你在when中遇到它。

匹配器的合同指出matches(Object)可以接受任何对象并返回true或false。这意味着在每一个匹配器实现,你都不应该假设传入的对象的类型,或者对象是否为非空;毕竟,isNull()是一个完全有效和有用的匹配器。如果您希望匹配器为任何空或非列表参数返回false,则应该手动检查该匹配项,或者扩展TypeSafeMatcher<List>而不是BaseMatcher,以便在这些情况下Hamcrest可以返回false。否则,你冒着未被捕获的ClassCastException或NullPointerException,这就是你在这里得到的。这是唯一真正的问题,修复它将解决您的麻烦。


这是一个好时机,不过,来解释的Mockito的语法。第一条线没有问题,那么为什么第二条线会失败?答案是,当你的第二个行运行:

when(mock.someMethod(argThat(hasSize(3)))).thenReturn([]) 

...那么Java评估呼叫when,所以它运行:

 mock.someMethod(argThat(hasSize(3))) 

...然后when可以检测someMethod作为最后调用的方法并开始其存根。与所有其他Mockito匹配器一样,argThat的调用返回null(保留其副作用,Mockito可以分析Java何时调用when),但someMethod必须具有返回值,Mockito无法检测到您是关于致电when。这意味着检查现有的存根,因此它将nullargThat管入您的匹配器中,以查看它是否应用您的第一个存根,这会导致NullPointerException。 (我放多一点关于argThat的返回值和another SO answer的Mockito的评估顺序。)

你无论如何要修理你的匹配器,但它也可以让你有改写第二行,如下所示:

doReturn([]).when(mock).someMethod(argThat(hasSize(3))) 

...因为someMethod之前调用when意味着可以的Mockito暂时解除您的存根。只要第一行不会抛出异常或调用实际的实现,但将语法保留为when并没有什么坏处,而Mockito会优雅地处理验证。