注释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)));
}
}
问题是当我们模拟假的组件B时。然后,someShimmedMethod将返回null。似乎InjectMock无法将mock()携带到私有成员。
以下是一些术语定义:
>
StubComponent:测试将作为私有成员渗透到这个组件。但是,有些方法可能无法通过。我们可以改变它的公共方法。该组件可能具有较小的依赖范围,很容易由本地资源发起。
FakeComponent:该组件将在其他地方测试。在这里,我们只能构建模拟实例并填充测试目标将利用的所有方法。
存根:@Spy可以帮助我们钩住存根成员。私人会员并非百分之百真实。但一些留有树桩的部分可能会让测试渗透到这个私人成员中。
Shim:@Mock会给我们一个空指针,直到initMocks。所以我们可以在initMocks之后开始设计Fake组件的返回。这就是@InjectMocks的魔力。然而,这是最棘手的部分,因为开发人员希望直观地启动组件B的每一件事并模拟(FakeComponent.class)。这将清理所有的闪光设计并使您的断言失败。
==================================================================
感谢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)));
}
}
第二个概念代码中添加了一些内容:
>
组件B是我们不想介入的范围。但是,TestTarget在其构造函数中初始化了组件B。当我们有一个与远程源相关的实用程序时,这很常见。我们使用mock服务器或其他技术独立测试组件B。因此,我们只能使用mock(TestTarget.class)。
因为我们模仿了TestTarget。我遗漏了一件事,那就是我们需要使用doCallRealMethod()。当(targetInstance)触发testInvokation()时。这限制了targetInstance的空声明。我们需要mock()并钩住doCallRealMethod。
因此,结果是我们需要将@Mock保留为空,而不使用任何mock()来让@InjectMocks处理垫片。我们刚刚发现当我们使用@InjectMocks时这很棘手。
问题在于@InjectMocks定义:
@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);
被测试的类永远不应该是mock(也是为什么是class关键字)。
尝试使用:
@InjectMocks
private TestTarget targetInstance = new TestTarget();
或者简单地说:
@InjectMocks
private TestTarget targetInstance;
所以我有一个类需要测试。我们把它叫做ClassToTest。它有两个Dao对象作为字段。 正如您所看到的,ClassToTest不包含任何构造函数或setter,我正在使用spring自动关联字段。 现在,我有了一个具有classToTest所需的所有依赖项的基本测试类: 并且testClass扩展了这个BaseTest类: 这将导致保存时出现空指针异常。但是,如果我将设置方法更改为: 考试通过了
例如,我有处理程序: 但是当我试图模拟它时,它实际上调用。如何使用来模拟它的方法?
我正在SpringMVC上使用Mockito进行JUnit测试。测试使用@InjectMock和@Mock with when(方法(…)。然后返回(X)。问题是如何在@Inject实例中@Mock方法? 我尝试过创建两个实例,例如@InjectMocks Foo foInstance和@Mock Foo foInstanceMock;我的思维方式是区分注入什么实例和嘲笑什么实例。我也尝试使用间谍
我有一个间接使用类Foo的测试用例。对于测试用例,我不在乎Foo是什么。我应该可以嘲笑它。 然而,testcase使用一个库来调用Foo上的一些方法。其中一些方法返回对象,然后该库对这些返回的对象调用一些方法。就本测试而言,这些对象是什么并不重要,只是它们不是null,并且不会导致NullPointerException。 对于该库调用的每个对象和方法,我已经经历并添加了一系列类似以下的expec
我正在用两个应用程序做project:android应用程序(客户端)和rest服务(服务器)。我的android应用程序消耗了我的rest服务。 这两个应用程序都是单独测试的,以确保它们按照预期完成业务。在服务器测试期间,我准备请求并检查服务器响应。在客户机测试期间,我设置了一个简单的http模拟服务器,并针对不同的模拟响应测试客户机的请求。 现在,这个技术很管用。它给了我一种我喜欢的灵活性。我
我想编写一些使用JUnit4.12、Mockito1.9.5和PowerMock1.6.1的单元测试。这个类有一些用@mock注释的字段,还有一些用@injectmocks注释的字段。用@InjectMocks注释的属性在某个点到达一个父构造函数,该父构造函数包含一些静态方法调用,应该用PowerMock来模拟。问题是第一个测试是无缝工作的,而第二个测试似乎根本没有嘲弄静态方法。 如前所述,第一个