Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单元测试Java代码-模拟不同类的非静态方法_Java_Unit Testing_Mockito_Powermock_Jmockit - Fatal编程技术网

单元测试Java代码-模拟不同类的非静态方法

单元测试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

这里我想测试类“First”的方法“doSecond()。同样,我想模拟类“Second”的方法“doJob”

我知道我可以使用下面的代码创建类“Second”的模拟实例

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模拟返回的工厂对象的结果

  • Second
    的实例传递给该方法,并使用Mockito作为mock实例

  • 将其声明为字段(即注入依赖项),并使用Mockito


为了完整起见,以下是如何使用JMockit mocking API编写测试,而无需对测试中的原始代码进行任何重构:

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