Mockito:如何validation在方法中创build的对象上调用的方法?

我是Mockito新手。

鉴于下面的类,我如何使用Mockito来validation在调用foo之后一次调用someMethod

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

我想进行下面的validation电话,

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

barbar的一个嘲弄的例子。

dependency injection

如果您注入Bar实例或用于创buildBar实例的工厂(或其他483种方法之一),则您必须具有访问权限才能执行testing。

工厂示例:

鉴于这样写的Foo类:

 public class Foo { private BarFactory barFactory; public Foo(BarFactory factory) { this.barFactory = factory; } public void foo() { Bar bar = this.barFactory.createBar(); bar.someMethod(); } } 

在你的testing方法中,你可以像这样注入一个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如何驱动代码devise的一个例子。

经典的回答是“你不要”。 你testingFoo的公共API,而不是它的内部。

有没有Foo对象的任何行为(或者,在环境中不太好,还有一些对象)受到foo()影响? 如果是的话,testing一下。 如果不是,该方法做什么?

如果你不想使用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 } } 

而你的testing课:

 @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对象。

希望它有帮助。

使用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输出 JUnit输出

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

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

我认为Mockito @InjectMocks是要走的路。

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

  1. build设者注入
  2. 物业二传注射
  3. 现场注射

更多信息在文档中

下面是一个实地注入的例子:

类别:

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

testing:

 @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(); } }