Mockito:如何从另一个singelton类

时间:2015-12-28 11:42:49

标签: java unit-testing junit singleton mockito

我是单元测试和Mockito的新手,如何为给定的单例代码片段编写测试代码。

1。我想为XYZ类编写单元测试。
2。我想验证方法是否被调用。
第3。我想编写测试代码来检查临时变量的状态。
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();

1 个答案:

答案 0 :(得分:4)

尝试回答

  

Mockito:如何验证由另一个单例的方法调用触发的单例中的方法调用?

关于

XYZ.getInstance().calculateSquare();

假设您只想使用Mockito和JUnit。

回答 :您的"虚拟代码"是不可测试代码的完美示例。

  • 您的示例代码不会向外部公开任何可观察的行为。 "外面"将是您尚未编写的周围测试代码,用于执行您的"虚拟代码"。 (所以)你不能对你的"虚拟代码"做出任何断言(JUnit / Hamcrest)。
  • 通过使用单身人士,你无法控制内心状态"您的"虚拟代码"虽然它正在测试中。 (所以)你不能对你的"虚拟代码"的行为进行任何验证(Mockito)。
  • 您无法直接测试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));
 }

那么为什么单身人士仍然不适合进行测试? 单身人士不能轻易替换为"占位符"用于测试目的的实例。这样的占位符可以是您对Abc TestAbc extends Abc或Mockito模拟的Abc实例的特殊测试实现。

最后, 如果您先编写测试 (!),您将永远不会编写您的"虚拟代码"就这样。

免责声明:以上代码旨在让您了解如何进行测试以及您的“虚拟代码”和#34;需要使其可测试。这并不意味着有意义的测试或这些示例按原样编译。