我是Mockito的新手。

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

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

我想打电话确认一下,

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

其中bar是bar的模拟实例。


当前回答

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

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

其他回答

我认为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();
    }
}

如果您不想使用DI或工厂。你可以用一种小技巧重构你的类:

public class Foo {
    private Bar bar;

    public void foo(Bar bar){
        this.bar = (bar != null) ? bar : new Bar();
        bar.someMethod();
        this.bar = null;  // for simulating local scope
    }
}

和你的测试类:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock Bar barMock;
    Foo foo;

    @Test
    public void testFoo() {
       foo = new Foo();
       foo.foo(barMock);
       verify(barMock, times(1)).someMethod();
    }
}

然后调用foo方法的类会这样做:

public class thirdClass {

   public void someOtherMethod() {
      Foo myFoo = new Foo();
      myFoo.foo(null);
   }
}

正如你所看到的,当以这种方式调用方法时,你不需要在任何其他调用foo方法的类中导入Bar类,这可能是你想要的。

当然,缺点是您允许调用者设置Bar对象。

希望能有所帮助。

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

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

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

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

使用PowerMockito.whenNew的示例代码的解决方案

mockito-all 1.10.8 powermock-core 1.6.1 powermock-module-junit4 1.6.1 powermock-api-mockito 1.6.1 junit 4.12

FooTest.java

package foo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

//Both @PrepareForTest and @RunWith are needed for `whenNew` to work 
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Foo.class })
public class FooTest {

    // Class Under Test
    Foo cut;

    @Mock
    Bar barMock;

    @Before
    public void setUp() throws Exception {
        cut = new Foo();

    }

    @After
    public void tearDown() {
        cut = null;

    }

    @Test
    public void testFoo() throws Exception {

        // Setup
        PowerMockito.whenNew(Bar.class).withNoArguments()
                .thenReturn(this.barMock);

        // Test
        cut.foo();

        // Validations
        Mockito.verify(this.barMock, Mockito.times(1)).someMethod();

    }

}

JUnit输出