我遇到了一些如何正确测试此代码的问题。我希望能够使用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;
}
}
答案 0 :(得分:6)
您无法创建Foo
类实例的原因是因为它是abstract
。 Java中没有可以创建抽象类实例的机制。
要测试抽象类,您需要定义将扩展Foo的新类。这意味着将调用默认构造函数。
答案 1 :(得分:1)
正如其他人所指出的那样,由于类的抽象性,你无法直接对Foo
构造函数类做任何事情。
话虽如此,如果您以稍微不同的方式考虑它,您应该能够为Bar
课程编写测试。而不是模拟Foo
构造函数调用,模拟DelegateForFoo
构造函数调用。
我想我会这样做:
所以它看起来像这样: (我为任何拼写错误道歉,我在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 documentation以了解有关使用PowerMock进行构造函数模拟的更多信息。
答案 2 :(得分:0)
让子类访问私有成员的唯一方法是拥有一个扩展抽象类的嵌套类。这样你就有了一个可以访问私有成员但没有其他类可以访问的类。