Mockito可以在不考虑参数的情况下存根方法吗?

Eri*_*son 283 java unit-testing mocking mockito

我正在尝试使用Mockito测试一些遗留代码.

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

foo = fooDao.getBar(new Bazoo());
Run Code Online (Sandbox Code Playgroud)

我可以写:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);
Run Code Online (Sandbox Code Playgroud)

但显而易见的问题是,getBar()永远不会使用Bazoo我为该方法存根的相同对象调用.(诅咒那个new操作员!)

如果我能以一种myFoo不管参数而返回的方式存根方法,我都会喜欢它.如果做不到这一点,我会听取其他的解决方法建议,但我真的希望避免更改生产代码,直到有合理的测试覆盖率.

Tom*_*icz 435

when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);
Run Code Online (Sandbox Code Playgroud)

或(避免nulls):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);
Run Code Online (Sandbox Code Playgroud)

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

对于Mockito 2.1.0和更新版本:

import static org.mockito.ArgumentMatchers.*;
Run Code Online (Sandbox Code Playgroud)

对于旧版本:

import static org.mockito.Matchers.*;
Run Code Online (Sandbox Code Playgroud)

  • 有一个`notNull(Bazoo.class)`就像`any(Bazoo.class)`(也许它在这个答案时不存在) (9认同)
  • 当答案在"接受答案冻结"结束之前,我喜欢它. (2认同)
  • 我有一个稍微特别的情况,我可以有两个可能的参数 - "Bazoo"或"Cazoo",它们都是,比如说'Azoo`的子类.对于'Bazoo`我需要返回`foo`,但对于`Cazoo`我需要返回`bar`.在这种情况下,提出的`Matchers.any()`解决方案不起作用,但是,`Matchers.isA()`工作正常. (2认同)
  • `org.mockito.Matchers`现已弃用 - 请改用`org.mockito.ArgumentMatchers`,即`import static org.mockito.ArgumentMatchers.*`(参见[docs](https://static.javadoc.io/org) .mockito /的Mockito核/ 2.10.0 /组织/的Mockito/Matchers.html)) (2认同)

小智 15

使用这样:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);
Run Code Online (Sandbox Code Playgroud)

在您需要导入之前 Mockito.Matchers

  • 这是贬义! (2认同)

Buh*_*uhb 13

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

anyObject应该符合您的需求.

此外,您始终可以考虑为Bazoo类实现hashCode和equals.这将使您的代码示例按您希望的方式工作.

  • Matchers 类已弃用(请参阅[文档](https://static.javadoc.io/org.mockito/mockito-core/2.10.0/org/mockito/Matchers.html) - _“此类可能会被删除在 3.0 版本中"_) (2认同)

Jos*_*nez 6

另一种选择是依靠良好的老式equals方法。只要whenmock中的参数equals与被测试代码中的参数一致,那么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 );
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,假设您知道其价值someField是什么,您可以像这样嘲笑它。

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);
Run Code Online (Sandbox Code Playgroud)

优点:这比any匹配器更明确。作为代码审阅者,我密切关注any初级开发人员编写的代码,因为它会浏览他们的代码逻辑以生成传递的适当对象。

缺点:有时传递给对象的字段是随机 ID。对于这种情况,您无法轻松地在模拟代码中构造预期的参数对象。

Answer另一种可能的方法是使用可与该方法一起使用的Mockito对象whenAnswer允许您拦截实际调用并检查输入参数并返回模拟对象。在下面的示例中,我用于any捕获对被模拟方法的任何请求。但随后在Answerlambda 中,我可以进一步检查 Bazo 参数...也许可以验证是否向其传递了正确的 ID。我更喜欢这个而any不是它本身,这样至少可以对论证进行一些检查。

    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;
    } );
Run Code Online (Sandbox Code Playgroud)

总而言之,我喜欢依赖equals(预期参数和实际参数应该彼此相等),如果 equals 不可能(由于无法预测实际参数的状态),我将诉诸来Answer检查参数。