我是Mockito的新手。

给定下面的类,我如何使用Mockito来验证someemethod在foo被调用后恰好被调用一次?

public class Foo
{
    public void foo(){
        Bar bar = new Bar();
        bar.someMethod();
    }
}

我想打电话确认一下,

verify(bar, times(1)).someMethod();

其中bar是bar的模拟实例。


当前回答

我认为Mockito @InjectMocks是正确的选择。

根据你的意图,你可以使用:

构造函数注入 属性setter注入 字段注入

文档中的更多信息

下面是一个字段注入的例子:

类:

public class Foo
{
    private Bar bar = new Bar();

    public void foo() 
    {
        bar.someMethod();
    }
}

public class Bar
{
    public void someMethod()
    {
         //something
    }
}

测试:

@RunWith(MockitoJUnitRunner.class)
public class FooTest
{
    @Mock
    Bar bar;

    @InjectMocks
    Foo foo;

    @Test
    public void FooTest()
    {
        doNothing().when( bar ).someMethod();
        foo.foo();
        verify(bar, times(1)).someMethod();
    }
}

其他回答

我今天遇到了这个问题,我不想使用PowerMock或其他东西。我只是想做一个测试,确保某个方法被调用。我找到了这篇文章,发现没有人提到过这种方法。

有一种方法可以在不增加更多依赖或类似的情况下实现这一点,技术含量相当低,但它是有效的:

@Test
public void testSomeMethodIsCalledOnce() throws Exception {
    final AtomicInteger counter = new AtomicInteger(0);
    Mockito.when(someObject.theMethodIWant(anyString()))
        .then((Answer<ReturnValue>) __ -> {
            teller.incrementAndGet();
            return theExpectedAnswer;
        });
    theObjectUnderTest.theMethod(someTestValue);

    assertEquals(1, teller.get());
}

这很简单,很容易看出发生了什么。当我想要的方法被调用时(这里是模拟的),做这些事情。其中有一个调用incrementAndGet来获取AtomicInteger。你可以在这里使用int[],但在我看来,这并不清楚。我们用的是最终值,可以加。这是我们用的的极限。

这有点粗糙,但它以简单而直接的方式完成了工作。至少如果你知道你的羔羊和Mockito。

另一种简单的方法是向bar.someMethod()中添加一些日志语句,然后确定在测试执行时可以看到所述消息,参见示例:如何对日志记录器中的消息执行JUnit断言

当你的Bar.someMethod()是私有的时候,这是特别方便的。

最经典的回答是:“你不需要。”你测试的是Foo的公共API,而不是它的内部。

Foo对象(或者,不太好,环境中的其他对象)是否有任何行为受到Foo()的影响?如果是,测试一下。如果不是,该方法做什么?

依赖注入

如果您注入Bar实例,或用于创建Bar实例的工厂(或其他483种方法中的一种),您将拥有执行测试所需的访问权限。

工厂的例子:

给定一个这样的Foo类:

public class Foo {
  private BarFactory barFactory;

  public Foo(BarFactory factory) {
    this.barFactory = factory;
  }

  public void foo() {
    Bar bar = this.barFactory.createBar();
    bar.someMethod();
  }
}

在你的测试方法中,你可以像这样注入一个BarFactory:

@Test
public void testDoFoo() {
  Bar bar = mock(Bar.class);
  BarFactory myFactory = new BarFactory() {
    public Bar createBar() { return bar;}
  };
  
  Foo foo = new Foo(myFactory);
  foo.foo();

  verify(bar, times(1)).someMethod();
}

奖励:这是TDD(测试驱动开发)如何驱动代码设计的一个例子。

是的,如果你真的想要/需要这样做,你可以使用PowerMock。这应该被视为最后的手段。使用PowerMock,可以使它从对构造函数的调用中返回一个模拟。然后在模拟上进行验证。也就是说,csturtz的答案是“正确的”。

这里是新对象的模拟构造的链接