我的代码如下:
public class RealWorldBoImpl extends AbstractBoImpl<T> implements SomeBo{}
和
@RunWith(PowerMockRunner.class)
@PrepareForTest({RealWorldBoImpl.class})
public class RealWorldBoImplTest {
@InjectMocks
private RealWorldBoImpl realWorldBo;
@Mock
private RealWorldDAO realWorldDAO;
@Test
public void changeStatusMainSubString() throws Exception {
long id = 1L;
}
在这种情况下,realWorldDAO无法注入realWorldBo。但是当我删除PrepareForTest时,它可以工作。
我也尝试了其他课程,它们效果很好。似乎RealWorldBoImpl的特殊之处在于,在进行准备时,它将无法正确注入模拟。
我调试了这段代码,发现在org.mockito.internal.util.reflection.FieldInitializer#checkParameterized中,constructor.getParameterTypes()不为空,并且具有带有IndicateReloadClass类的构造函数。
private void checkParameterized(Constructor<?> constructor, Field field) {
if(constructor.getParameterTypes().length == 0) {
throw new MockitoException("the field " + field.getName() + " of type " + field.getType() + " has no parameterized constructor");
}
}
但是我不知道RealWorldBoImpl有什么特别之处。它只是扩展了父类并实现了一个接口。有关系吗?
答案 0 :(得分:0)
当PowerMock准备一个具有除Object
以外的超类的类时,它将向该类添加一个构造函数,该构造函数接受类型为org.powermock.core.IndicateReloadClass
的参数。
为什么PowerMock会这样做? PowerMock通过此机制实现超类构造函数抑制。
在您的情况下,因为RealWorldBoImpl
源自AbstractBoImpl
,PowerMock将以下构造函数添加到RealWorldBoImpl
,AbstractBoImpl
类中:
public RealWorldBoImpl(IndicateReloadClass var1) {
super(var1);
}
public AbstractBoImpl(IndicateReloadClass var1) {
super(); //assuming the parent class is Object otherwise super(var1)
}
并将RealWorldBoImpl
的默认no-arg构造函数更改为以下内容:
public RealWorldBoImpl() {
Object var1 = MockGateway.constructorCall(Desc.getClazz("org.example.RealWorldBoImpl"),
new Object[0], Desc.getParams("()V"));
if (var1 != MockGateway.PROCEED) {
super((IndicateReloadClass)null);
} else {
super();
}
}
那是PowerMock的一部分,现在让我们进入Mockito的部分。
Mockito有两种注入策略(MockInjectionStrategy
):ConstructorInjection
和PropertyAndSetterInjection
。
ConstructorInjection
使用构造函数注入模拟,并在被注入者具有至少一个非默认构造函数(至少接受一个参数的构造函数)时使用。如果被注入者只有一个无参数构造函数,则Mockito使用PropertyAndSetterInjection
来使用setter方法,如果没有setter方法,则通过反射设置字段的值来直接注入模拟。
在您的情况下,当您准备RealWorldBoImpl
类时,您有一个带有一个参数的构造函数,而Mockito使用ConstructorInjection
通过PowerMock添加的构造函数向对象注入模拟对象(并且没有模拟对象)类型为IndicateReloadClass
的Mockito将null传递给构造函数,但这无关紧要,因为构造函数什么也不做),因此不会注入任何模拟。
那么您如何解决问题?如果要注入多个模拟,请向注入对象类中添加一个构造函数,该构造函数的参数与要注入的模拟数量一样多。只要您的构造函数具有多个参数,注入就可以工作,否则您的被注入者类应具有Object
作为其超类。
如果仅要注入一个模拟,则可以向构造函数添加一个虚拟参数,以使Mockito选择由PowerMock添加的构造函数:
public RealWorldBoImpl(RealWorldDAO realWorldDAO, String dummy) {
this.realWorldDAO = realWorldDAO;
}