模拟内部实例化对象

时间:2011-12-15 09:37:55

标签: java testing mocking

我正在编写一个测试类来测试我的'ImporterService'类。此服务读取InputStream并从其数据创建Object。 Object(在本例中为Builder类)在“ImporterService”类中实例化。要测试我的'ImporterService'类,我需要验证Builder类的调用。为此,我想使用Mocking框架,但是如何在'ImporterService'之外创建'Builder'对象的模拟实例?

我的'ImporterService'类的方法如下:



    public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = new Builder();   // I need to mock this Builder object...
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }

我正在考虑将Builder类的创建转移到受保护的方法中,我可以在测试设置时覆盖它。但是这个解决方案对我来说似乎并不是很好,因为'ImporterService'类正在泄漏一些内部逻辑,并且可以通过我不想要的其他类来覆盖该方法。

5 个答案:

答案 0 :(得分:2)

如果您使用任何依赖注入库(如Spring),您可以将模拟对象而不是构建器注入ImporterService类。或者你可以用对工厂的调用替换对构造函数的调用,并使用工厂,它会在测试代码中返回模拟。

答案 1 :(得分:1)

是的,你可以按照你的建议做或:

创建一个Factory类,在其中创建Builder个对象并将其分配给reader类。在您的单元测试中,模拟此工厂并强制它构建您选择的Builder,您可以在单元测试中检查方法调用。

以下是使用EasyMock显示如何实现此目的的示例:

public class Reader{
   private BuilderFactory factory = new BuilderFactory(); // Use production factory by default
   public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = factory.buildBuilder();
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }
}

在您的单元测试中,您执行以下操作:

Reader classUnderTest = new Reader();
BuilderFactory fakeFactory = EasyMock.createNiceMock(BuilderFactory.class);
Builder builder = EasyMock.createMock(Builder.class);
EasyMock.expect(fakeFactory.buildBuilder()).andReturn(builder);
builder.someMethod("value here");
EasyMock.expectLastCall().once();
EasyMock.replay(fakeFactory, builder);
classUnderTest.importFrom(bufferReader);
// Very that all calls were correctly performed on the builder
EasyMock.verify(builder);

答案 2 :(得分:0)

假设您正在使用Mockito(我推荐这个模拟框架),您将能够执行以下操作:

  @Test
    public void testFoo(@Mocked Builder builder) {
        new Expectations() {
            {
                new Builder();
                returns(builder);

                builder.setSomemethod()
                ...
            }
        };

        assertSame(builder,impoertesService.importFrom(...));
    }

答案 3 :(得分:0)

某些模拟框架(如PowerMock)可以模拟对象的构造。

答案 4 :(得分:0)

您可以将功能签名更改为以下内容:

public Builder importFrom(BufferedReader reader, Builder builder) throws IOException {

通过这样做,您可以从测试用例中传递任何虚拟实现。这是依赖注入的一种方式。

依赖注入的想法是要求所有依赖项,如果类/函数执行此操作,则代码变得高度可测试。

相关问题