java - Mockito:如何在方法中创建的对象上调用方法?
我是Mockito的新手。
鉴于下面的课程,如何在调用Bar之后使用Mockito来验证bar是否被调用了一次?
public class Foo
{
public void foo(){
Bar bar = new Bar();
bar.someMethod();
}
}
我想进行以下验证通话,
verify(bar, times(1)).someMethod();
其中bar是Bar的模拟实例。
7个解决方案
259 votes
依赖注入
如果您注入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如何推动代码设计的一个例子。
csturtz answered 2019-03-05T09:44:39Z
18 votes
经典的回答是,“你没有。” 您测试Foo的公共API,而不是其内部。
是否存在受foo()影响的Foo对象(或不太好,环境中的其他对象)的任何行为? 如果是这样,请测试一下。 如果没有,该方法有何作用?
Michael Brewer-Davis answered 2019-03-05T09:45:13Z
10 votes
如果您不想使用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 Object。
希望能帮助到你。
raspacorp answered 2019-03-05T09:46:08Z
7 votes
我认为Mockito @InjectMocks是要走的路。
根据您的意图,您可以使用:
构造函数注入
物业二传手注射
现场注射
更多信息在docs中
以下是现场注入的示例:
类别:
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();
}
}
siulkilulki answered 2019-03-05T09:47:27Z
6 votes
使用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输出
javaPlease42 answered 2019-03-05T09:48:37Z
3 votes
是的,如果您真的想要/需要这样做,您可以使用PowerMock。 这应该被视为最后的手段。 使用PowerMock,您可以使它从调用返回模拟构造函数。 然后在模拟上进行验证。 也就是说,csturtz是“正确”的答案。
这是Mock构造新对象的链接
John B answered 2019-03-05T09:49:10Z
0 votes
另一个简单的方法是将一些日志语句添加到bar.someMethod(),然后确定您可以在执行测试时看到所述消息,请参阅此处的示例:如何在记录器中对消息执行JUnit断言
当你的Bar.someMethod()是private时,这是特别方便的。
Nestor Milyaev answered 2019-03-05T09:49:43Z