簡體   English   中英

Mockito:如何從另一個Singelton類驗證Singelton類的方法調用

[英]Mockito: how to verify method call of a singelton class from another singelton class

我是單元測試和Mockito的新手,如何為給定的代碼片段(單例)編寫測試代碼。

1.我想為XYZ類編寫單元測試。
2.我想驗證方法是否被調用。
3.我想編寫測試代碼以檢查temp變量的狀態。
4.我也想為專用方法計算器編寫測試代碼。

ABC類是單例,具有兩個字段num和square。

class ABC{
      private static ABC instance;
      private int num;
      private int square;

      private ABC() {}

      public static ABC getInstance() {
          if (instance == null) {
              instance = new ABC();
          }
          return instance;
      }

      public int getSquar() {
          return square;
      }

      public void setSquar(int square) {
          this.square = square;
      }

      public int getNum() {
          return num;
      }

      public void setNum(int num) {
          this.num = num;
      }
}

XYZ類(單例)正在調用getter,而ABC類中的setter也是單例。

class XYZ{
     private static XYZ instance;
     private int result;

     private XYZ(){}

     public static XYZ getInstance(){
          if (instance == null) {
              instance = new XYZ();
          }
          return instance;
     }

     public void calculateSquare(){
         ABC.getInstance().setNum(5);
         int n = ABC.getInstance().getNum();
         result = calculator(n);
         ABC.getInstance().setSquare(result);

     }  

     private int calculator(int n){
         return n*n;
     }
}

在這里,我正在調用類XYZ的calculateSquare方法。

XYZ.getInstance().calculateSquare();

試圖回答

Mockito:如何驗證由另一個單例的方法調用觸發的單例中的方法調用?

關於

XYZ.getInstance().calculateSquare();

假設您只想使用Mockito和JUnit。

:您的“虛擬代碼”是無法測試的代碼的完美示例。

  • 您的示例代碼不會向外界暴露任何可觀察到的行為。 “外部”將是行使您的“虛擬代碼”的尚未編寫的周圍測試代碼。 (因此)您不能對“虛擬代碼”做出任何斷言(JUnit / Hamcrest)。
  • 通過使用Singleton,您將無法在測試期間控制“虛擬代碼”的“內部狀態”。 (因此)您無法對“虛擬代碼”的行為進行任何驗證(模擬)。
  • 您不能直接測試private方法,因為您不能調用它們。 如果您認為需要測試private方法,則不應將其private

    私有方法隱藏了您不應該針對其編寫任何測試的內部實現。 針對公共API測試編寫測試以了解預期的行為,而不是針對該行為的實現方式編寫代碼(該行為可能由於任何原因而隨時更改,從而很容易破壞您的測試)。

如果要測試代碼,則必須對其進行設計/編碼以使其可測試 JUnit / Mockito無法為您使不可測試的代碼可測試。


提示:

用一個簡單的構造函數代替Singleton方法,該構造函數采用實例完成其工作所需的任何依賴的協作者 結果變成

public Xyz(final Abc yourCollaborator) {
    this.collaborator = yourCollaborator;
}

使用的Mockito可以創建你的模擬或間諜實例Abc.class 您需要一個經過模擬的Abc實例,以將其傳遞到Xyz構造函數中,以進行驗證。 像這樣:

@Test
public void calculateSquareShouldSetNumTo5() throws Exception {
    Abc mockedAbc = Mockito.mock(Abc.class);
    Xyz xyz = new Xyz(mockedAbc);

    // method under test
    xyz.calculateSquare();

    Mockito.verify(mockedAbc).setNum(5); // expect setNum(5) to be called once
}

要真正對實現進行斷言 ,您需要一個Abc類的真實實例。 因為它是您可以觀察“ calculateSquare()方法調用的效果”的“部分”。 (請注意,您不能為此使用Mockito模擬的Abc實例!)您的測試可能如下所示:

 @Test
 public void calculateSquareShouldAlwaysResult25() throws Exception {
     Abc abc = new Abc();
     Xyz xyz = new Xyz(abc);

     // method under test
     xyz.calculateSquare();

     assertThat(abc.getSquare(), is(25));
 }

實際上,最后的測試也可以照原樣為您的“虛擬代碼”編寫:

 @Test
 public void calculateSquareShouldAlwaysResult25() throws Exception {
     // method under test
     XYZ.getInstance().calculateSquare();

     assertThat(ABC.getInstance().getSquare(), is(25));
 }

那么,為什么Singletons仍然對測試不利? 出於測試目的,不能輕易用“占位符”實例替換單例。 這樣的占位符可以是Abc的特殊測試實現,也可以是TestAbc extends Abc或Mockito模擬的Abc實例。

最后, 如果您將首先編寫測試 (!),則您永遠不會以這種方式編寫“虛擬代碼”。

免責聲明:上面的代碼旨在讓您了解如何進行測試以及“虛擬代碼”需要進行哪些更改才能使其可測試。 這並不意味着有意義的測試,也不意味着這些示例按原樣進行編譯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM