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


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的能力

https://code.google.com/p/powermock/wiki/MockConstructor

不需要修改任何源代码。

下面是测试代码,当First.doSecond()调用new Second()

时,我们实际上返回了一个mock
@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);
    }
}

相关内容

  • 没有找到相关文章

最新更新