单元测试Java代码-模拟不同类的非静态方法
这里我想测试类“First”的方法“doSecond()。同样,我想模拟类“Second”的方法“doJob” 我知道我可以使用下面的代码创建类“Second”的模拟实例单元测试Java代码-模拟不同类的非静态方法,java,unit-testing,mockito,powermock,jmockit,Java,Unit Testing,Mockito,Powermock,Jmockit,这里我想测试类“First”的方法“doSecond()。同样,我想模拟类“Second”的方法“doJob” 我知道我可以使用下面的代码创建类“Second”的模拟实例 public class First { public First(){ } public String doSecond(){ Second second = new Second(); return second.doJob(); } } class S
public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
但从当前代码开始,我无法将这个模拟实例与类“First”关联起来。
在不重构源代码的情况下,是否有任何方法可以实现需求。
请提供帮助。看看powermock拦截调用
new
并返回mock的能力
这不需要更改任何源代码
下面是测试代码,当First.doSecond()调用new Second()
模拟在方法内部创建的实例很棘手,但这是可能的 使用PowerMock,您可以通过以下方法完成此任务: 实际上,PowerMock代理创建新对象,并在调用
doSecond()
时替换我们想要的任何值
所以,这是可能的。然而,这是一个非常糟糕的练习
典型地,如果对象涉及外部关注,例如另一层(即数据库、验证),或者如果期望的输出来自注入的其他对象,但安全性足以考虑测试,则需要模拟对象。 如果您的方法能够从不可注入的源获取或检索数据,那么您不应该想模仿它
考虑到您的方法简单明了,您实际上根本不需要在这里进行任何模拟。但如果你觉得自己是被迫的,你可以做以下几件事之一:- 创建一个工厂以创建第二个,并用Mockito模拟返回的工厂对象的结果
- 将
的实例传递给该方法,并使用Mockito作为mock实例Second
- 将其声明为字段(即注入依赖项),并使用Mockito
@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!!!"));
}
}
如果这两个方法有不同的名称,那么这将非常容易理解。我还以为你是在模拟测试中的方法呢。另一方面,如果
First.doSecond
真的像这里描述的那样简单,你可能不应该测试它,因为你只是通过代理测试Second.doSecond
。好的,我怎么解决它呢。你能把答案贴出来吗。在实际场景中,方法名称是不同的。@ChrisHayes这只是一个小例子来解释我现在面临的真正问题。请帮忙。很好地处理这种情况。我建议你仔细阅读它,并决定它是否适合你的项目,而更改源代码可能是最好的方法。OP特别要求提供一种不需要更改源代码的解决方案。我参与过许多项目,其中有一个庞大的遗留代码库,必须进行维护和测试,但没有时间或预算来重构糟糕的设计。PosiMoCK解决方案是用来满足这一需求的创可贴。是的,但是编写测试的时间通常是足够的时间来重构,以使它们在某些情况下更容易测试。对我来说,这似乎非常非常奇怪,人们想要模拟创建一个新实例,而不是注入或传入它。@Makoto反对模拟非注入依赖项的论点非常弱。依赖项是否被注入与是否模拟的决定无关。重要的是依赖关系是落在“被测单元”的内部还是外部;如果它在外部,并且您希望编写具有适当隔离的单元测试,那么您需要模拟依赖关系。对于一个真实世界的例子,考虑使用Apache CAMONS电子邮件API的类:在这种情况下,您当然想模拟<代码>电子邮件< /Cord>子类,即使它通常被实例化而不是注入。
@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());
}
}
@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!!!"));
}
}
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);
}
}