[英]The deep mock is not working as member of @InjectMocks
注释@InjectMocks
为我们提供了对存根/填充私有成员@InjectMocks
的方法。 这是当我们对假成员进行伪造时发生问题的概念代码。
public class TestBuilder{
@Spy
private StubComponent componentA = new StubComponent();
@Mock
private FakeComponent componentB;
@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);
public static Class TestTarget{
private StubComponent componentA;
private FakeComponent componentB;
public ShimmedResultB testInvokation(String para){
componentA.doCallRealMethod();
ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
return shouldNotBeNull;
}
}
private TestBuilder(){
MockitoAnnotations.initMocks(this);
//Shim the real component A with partial stubbed
doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());
//Shim the fake component B
//************The issue is here****************
componentB = mock(FakeComponent.class);
//*********************************************
when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);
}
public TestTarget getTargetInstance(){
return this.targetInstance;
}
public static TestTarget build(){
return (new TestBuilder()).getTargetInstance();
}
public static main(String[] args){
TestTarget testInstance = TestBuilder.build();
ShimmedResultB result = testInstance.testInvokation("");
assertThat(result, not(equalTo(null)));
}
}
问题是当我们模拟Fake componentB
。 然后someShimmedMethod
将返回null。 看来InjectMocks
无法将mock()
携带给私有成员。
以下是一些术语定义:
StubComponent:测试将作为私有成员渗透到此组件。 但是,有些方法可能无法通过。 我们可以使用其公开方法。 该组件可能具有较小的依赖性范围,这些依赖性范围很容易由本地资源启动。
FakeComponent:该组件将在其他地方进行测试。 在这里,我们只能构建模拟实例,并填充测试目标将利用的所有方法。
存根:@Spy可以帮助我们钩住存根成员。 私人成员不是100%真实的。 但是某些残存的部分可能会让测试渗透到该私有成员中。
Shim:@Mock将为我们提供一个空指针,直到initMocks。 因此,我们可以开始设计initMocks之后的Fake组件的返回。 这是@InjectMocks的魔力。 但是,这是最棘手的部分,因为开发人员希望直观地初始化componentB的所有内容并嘲笑(FakeComponent.class)。 这将清除所有填充的设计,并使您的声明失败。
================================================== ================
感谢Maciej的答复,对我翻译测试用例的结构时出现的错字表示抱歉。 并且让我对Maciej的答案进行更清晰的描述来提出这个问题。
public class TestBuilder{
@Spy
private StubComponent componentA = new StubComponent();
@Mock
private FakeComponent componentB;
@InjectMocks
private TestTarget targetInstance = mock(TestTarget.class);
public static Class TestTarget{
private StubComponent componentA;
private FakeComponent componentB;
public ShimmedResultB testInvokation(String para){
componentA.doCallRealMethod();
ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
return shouldNotBeNull;
}
public TestTarget(){
//The FakeComponent has some specific remote resource
//And could not be initialized here
componentB = new FakeComponent();
//We will use mock server to test this FakeComponent else where
}
}
private TestBuilder(){
//Hook the testing Function for trigger the step in
doCallRealMethod().when(this.targetInstance).testInvokation(anyString());
//Inject Stubbed and Faked Private Member for testing
MockitoAnnotations.initMocks(this);
//Shim the real component A with partial stubbed
doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());
//************The issue is here****************
componentB = mock(FakeComponent.class);
//*********************************************
//Shim the leveraged method of fake componentB
when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);
}
public TestTarget getTargetInstance(){
return this.targetInstance;
}
public static TestTarget build(){
return (new TestBuilder()).getTargetInstance();
}
public static main(String[] args){
TestTarget testInstance = TestBuilder.build();
//The doRealCall hook will trigger the testing
ShimmedResultB result = testInstance.testInvokation("");
assertThat(result, not(equalTo(null)));
}
}
第二个概念代码中添加了一些内容:
componentB是我们不希望介入的范围。但是,TestTarget在其构造函数中使用componentB进行初始化。 当我们有一个与远程源相关的工具时,这很常见。 我们使用模拟服务器或其他技术来独立测试componentB。 因此,我们只能使用模拟(TestTarget.class)。
由于我们嘲笑了TestTarget。 我错过了一件事,我们需要使用doCallRealMethod()。when(targetInstance)来触发testInvokation()。 这限制了targetInstance的空声明。 我们需要模拟()并挂钩doCallRealMethod。
因此,结果是我们需要将@Mock保留为空,而没有任何模拟()以便让@InjectMocks处理垫片。 当我们使用@InjectMocks时,我们发现这很棘手。
问题在于@InjectMocks定义:
@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);
被测类绝不能是模拟类(也是为什么要使用class关键字)。
尝试使用:
@InjectMocks
private TestTarget targetInstance = new TestTarget();
或者简单地:
@InjectMocks
private TestTarget targetInstance;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.