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();
bar
是bar
的一个嘲弄的例子。
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输出
是的,如果你真的想/需要这样做,你可以使用PowerMock。 这应该被认为是最后的手段。 使用PowerMock,你可以使它从调用返回一个模拟构造函数。 然后做模拟validation。 这就是说,csturtz是“正确”的答案。
这里是模拟新对象构build的链接
我认为Mockito @InjectMocks
是要走的路。
根据您的意图,您可以使用:
- build设者注入
- 物业二传注射
- 现场注射
更多信息在文档中
下面是一个实地注入的例子:
类别:
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(); } }