public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
这里我想测试类"First"的方法"doSecond()"。同样,我想模拟类"Second"的方法"doJob"。
我知道我可以使用下面的代码创建类"Second"的模拟实例。
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
但是我不能将这个模拟实例与当前代码中的类"First"联系起来。不重构源代码,是否有任何方法可以实现需求?请帮助。
看看powermock拦截对new
的调用并返回mock的能力
不需要修改任何源代码。
下面是测试代码,当First.doSecond()调用new Second()
@RunWith(PowerMockRunner.class)
@PrepareForTest(First.class)
public class TestFirst {
@Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
模拟在方法内部创建的实例是很棘手的,但这是可能的。
使用PowerMock,您可以使用PowerMock.expectNew()
方法完成此操作:
@RunWith(PowerMockRunner.class)
@PrepareForTest(First.class)
public class StackOverflowTest {
@Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
实际上,PowerMock正在代理新对象的创建,并在调用doSecond()
时替换我们想要的任何值。
所以是可能的。然而,这是一个糟糕的练习。
如果对象涉及外部关注点,例如另一层(即数据库、验证),或者如果期望的输出来自注入的其他对象,但足够安全,可以考虑进行测试,则通常希望模拟对象。
如果你的方法能够从一个不可注入的源中获取或检索数据,你不应该想要模拟它。
考虑到你的方法是简单和直接的,你应该真的不需要在这里做任何模拟。但如果你觉得你是被迫的,你可以做以下几件事之一:
为创建
Second
创建一个工厂,并使用Mockito模拟返回的工厂对象的结果。将
Second
的实例传递给该方法,并使用Mockito作为模拟实例。声明为一个字段(即注入依赖),并使用Mockito
为了完整起见,下面是如何使用JMockit mock API编写测试,而无需对测试中的原始代码进行任何重构:
public class ExampleTest
{
@Test
public void firstShouldCallSecond(@Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}