簡體   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