繁体   English   中英

如何调用抽象类的私有构造函数进行模拟。

[英]How to call a private constructor of an abstract class for mocking.

关于如何正确测试此代码,我遇到了一些问题。 我希望能够使用Mocking框架或甚至反射来模拟对delegateForFoo的调用。 但是,当我尝试通过反射或通过PowerMock执行此操作时,我会收到如下代码中所示的错误。

@Test
public void testDelegatedMethodWithPowerMock() throws Exception {

    DelegateForFoo mockedDelegateForFoo = PowerMock
            .createMock(DelegateForFoo.class);

    Foo foo = Whitebox.invokeConstructor(Foo.class, mockedDelegateForFoo);
    // org.powermock.reflect.exceptions.ConstructorNotFoundException: Failed
    // to find a constructor with parameter types: at line above.

    Constructor<Foo> fooConstructor = Foo.class
            .getDeclaredConstructor(DelegateForFoo.class);
    fooConstructor.setAccessible(true);
    Foo foo2 = fooConstructor.newInstance(mockedDelegateForFoo);
    // java.lang.InstantiationException at line above.

}

我尽力检查以前的stackOverflow问题,但我没有看到直接解决此问题的问题。 关于如何调用具体类的私有构造函数有一些答案,有些关于如何在抽象类上对私有方法进行分类,但在这个特定实例上没有。

我的官方问题如下:有没有办法调用抽象类的私有构造函数并传入一个模拟对象用于测试目的。

我知道通常你不应该测试私有方法等。但是在这种情况下,我想测试一个有正当理由是私有的构造函数。 Bar根本没有理由知道关于委托的任何事情,如果要进行适当的封装,它应该是私有的。 提前致谢。

我正在使用的代码如下。

public abstract class Foo {

    private DelegateForFoo delegateForFoo;
    private int valueToBeSetFromDelegate;

    Foo() {
        // I don't want the subclasses to do anything with this DelegateForFoo.
        // It's set through the constructor because there is a requirement that
        // Foo must have a delegateForFoo in order to be created.
        this(new DelegateForFoo());
    }

    // This Constructor is indirectly called by the subclasses. They don't know
    // anything about how it is set, or what it does.
    private Foo(DelegateForFoo delegateForFoo) {
        this.delegateForFoo = delegateForFoo;
        this.valueToBeSetFromDelegate = this.delegateForFoo.delegatedMethod();
    }

    int useTheDelegateForSomeMethod() {
        return this.delegateForFoo.delegatedMethod();
    }
}


public class DelegateForFoo {
    int delegatedMethod() {
        return 5;
    }
}



public class Bar extends Foo {
    // here, Bar doesn't care about the delegate for Foo at all. It only cares
    // that the method it is called has some implementation.
    int useDelegateForFooWithoutKnowingAboutIt() {
        return super.useTheDelegateForSomeMethod() + 10;
    }
}

你不能创建你的Foo类的实例的原因是因为它是abstract Java中没有可以创建抽象类实例的机制。

要测试抽象类,您需要定义将扩展Foo的新类。 这意味着将调用默认构造函数。

正如其他人所指出的那样,由于类的抽象性,你无法直接对Foo构造函数类做任何事情。

话虽如此,如果您以稍微不同的方式考虑它,您应该能够为Bar类编写测试。 而不是模拟Foo构造函数调用,模拟DelegateForFoo构造函数调用。

我想我会这样做:

  • 使用PowerMock准备Foo,Bar和DelegateForFoo类。
  • 为DelegateForFoo构造函数调用设置PowerMock Expectation,为其返回Mock对象。
  • 添加delegatedMethod的期望。
  • 创建一个Bar对象,然后调用useDelegateForFooWithoutKnowingAboutIt方法
  • 别忘了验证。

所以它看起来像这样:( 我为任何打字错误道歉,我没有在IDE中尝试过这个)

@RunWith( PowerMockRunner.class )
@PrepareForTest( Foo.class, Bar.class, DelegateForFoo.class )
public class BarTest

    @Test
    public void thatDelegateForFooCanBeMocked() {
        DelegateForFoo mockDelegate = EasyMock.createMock(DelegateForFoo.class);
        EasyMock.expect( mockDelegate.delegatedMethod() ).andReturn( 5 );
        EasyMock.replay( mockDelegate );

        PowerMock.expectNew( DelegateForFoo.class ).andReturn( mockDelegate );
        PowerMock.replayAll();

        Bar bar = new Bar();
        int result = bar. useDelegateForFooWithoutKnowingAboutIt();

        Assert.assertThat( result, CoreMatchers.is(15) );

        PowerMock.verifyAll();
        EasyMock.verify(mockDelegate);
    }
}

当然,文档是一件很棒的事情,所以请参阅PowerMock:Mocking a Constructor文档,以了解有关使用PowerMock进行构造函数模拟的更多信息。

让子类访问私有成员的唯一方法是使用嵌套类来扩展抽象类。 这样你就有了一个可以访问私有成员但没有其他类可以访问的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM