繁体   English   中英

深层模拟无法作为@InjectMocks的成员运行

[英]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()携带给私有成员。

以下是一些术语定义:

  1. StubComponent:测试将作为私有成员渗透到此组件。 但是,有些方法可能无法通过。 我们可以使用其公开方法。 该组件可能具有较小的依赖性范围,这些依赖性范围很容易由本地资源启动。

  2. FakeComponent:该组件将在其他地方进行测试。 在这里,我们只能构建模拟实例,并填充测试目标将利用的所有方法。

  3. 存根:@Spy可以帮助我们钩住存根成员。 私人成员不是100%真实的。 但是某些残存的部分可能会让测试渗透到该私有成员中。

  4. 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)));
      }
  }

第二个概念代码中添加了一些内容:

  1. componentB是我们不希望介入的范围。但是,TestTarget在其构造函数中使用componentB进行初始化。 当我们有一个与远程源相关的工具时,这很常见。 我们使用模拟服务器或其他技术来独立测试componentB。 因此,我们只能使用模拟(TestTarget.class)。

  2. 由于我们嘲笑了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.

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