我试图测试一些遗留代码,使用Mockito。

我想存根在生产中使用的FooDao如下:

foo = fooDao.getBar(new Bazoo());

我可以这样写:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);

但明显的问题是,getBar()从未使用我为该方法存根的同一个Bazoo对象调用。(该死的新接线员!)

如果我能以一种不管参数如何返回myFoo的方式存根这个方法,我会很高兴。如果做不到这一点,我将听取其他解决方案的建议,但我真的希望在有合理的测试覆盖率之前避免更改生产代码。


当前回答

when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

或(避免空):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

不要忘记导入匹配器(许多其他的匹配器可用):

对于Mockito 2.1.0及更新版本:

import static org.mockito.ArgumentMatchers.*;

对于旧版本:

import static org.mockito.Matchers.*;

其他回答

另一个选择是依靠传统的时尚等于方法。只要when mock中的参数等于被测试代码中的参数,那么Mockito将匹配mock。

这里有一个例子。

public class MyPojo {

    public MyPojo( String someField ) {
        this.someField = someField;
    }

    private String someField;

    @Override
    public boolean equals( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        MyPojo myPojo = ( MyPojo ) o;
        return someField.equals( myPojo.someField );
    }

}

然后,假设您知道someField的值是什么,您可以像这样模拟它。

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);

优点:这比任何匹配器都更明确。作为一名代码审查员,我密切关注初级开发人员编写的代码中的任何内容,因为它会检查他们的代码逻辑以生成传递的适当对象。

弊:有时传递给对象的字段是一个随机ID。对于这种情况,在模拟代码中不容易构造预期的参数对象。

Another possible approach is to use Mockito's Answer object that can be used with the when method. Answer lets you intercept the actual call and inspect the input argument and return a mock object. In the example below I am using any to catch any request to the method being mocked. But then in the Answer lambda, I can further inspect the Bazo argument... maybe to verify that a proper ID was passed to it. I prefer this over any by itself so that at least some inspection is done on the argument.

    Bar mockBar = //generate mock Bar.

    when(fooDao.getBar(any(Bazo.class))
    .thenAnswer(  ( InvocationOnMock invocationOnMock) -> {
        Bazo actualBazo = invocationOnMock.getArgument( 0 );

        //inspect the actualBazo here and thrw exception if it does not meet your testing requirements.
        return mockBar;
    } );

综上所述,我喜欢使用等号(期望的实参和实际实参应该彼此相等),如果不可能使用等号(由于无法预测实际实参的状态),我将使用Answer来检查实参。

像这样使用:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);

在您需要导入Mockito之前。匹配器

when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

或(避免空):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

不要忘记导入匹配器(许多其他的匹配器可用):

对于Mockito 2.1.0及更新版本:

import static org.mockito.ArgumentMatchers.*;

对于旧版本:

import static org.mockito.Matchers.*;

http://site.mockito.org/mockito/docs/1.10.19/org/mockito/Matchers.html

anyObject()应该适合您的需求。

此外,您总是可以考虑为Bazoo类实现hashCode()和equals()。这将使您的代码示例按您希望的方式工作。