JUnit我应该使用什么断言

时间:2018-12-26 21:14:21

标签: junit assert assertion

我想寻求帮助和建议,哪种情况是正确的方法(可能很简单,但我只是从JUnit开始)。这是我的代码的一部分

public boolean arrayListEmpty()
    {
        if(numericalSequence.isEmpty() == true)
            return true;
        else
            return false;
    }

这是模型中的一个公共方法,我想我应该测试一下,如果我的数值序列为空,则返回true。我不能直接调用numericSequence.isEmpty(在我需要的控制器中)检查它,因为它是私有的。 显而易见的是要检查

assertEquals(true, test.arrayListEmpty());

所以我的问题是关于建议我应该使用其他哪些主张/应该预测哪些情况可以提出的建议。我应该在Test方法中用一些值填充numericSequence并对其进行断言吗? (对我而言,这不是必需的,因为插入序列中的任何值都不是null,但是可能并不容易)

1 个答案:

答案 0 :(得分:2)

首先,欢迎您使用Stack Overflow!

看着您的问题,听起来您是单元测试的新手(如果我错了,请纠正我)。因此,我将答案分为两个部分: (1)回答您的问题,以及(2)为如何编写良好的测试和可测试的类提供总体指导。

1。回答您的问题

您可以在这里想到更多用例:

  1. 如果numericalSequencenull会发生什么?
  2. 如果numericalSequence有1个元素怎么办?
  3. 如果numericalSequence具有null元素怎么办?

上述某些情况可能无法实现,具体取决于您的类的设置方式,但这是一项值得拥有的测试,因此,违反这些测试用例之一的“先前约定的行为”的任何类更改都将失败

2。编写良好的测试

对于编写好的测试没有严格的指导方针,但是,如果您将代码结构化为可测试的,则会发现编写好的测试变得更加容易,并且会减少琐事。请允许我解释。

注意:这不是一本全面的指南,而是旨在开始您如何编写更好的代码和更好的测试之路

因此,假设需要测试的类是这样写的:

class MyClass {
  // NOTE: This is not `final`
  private List<Integer> numericalSequence;

  public MyClass() {
    this.numericalSequence = new ArrayList<>();
  }

  public void doSomething(Integer x) {
    if (x < 0) {
      numericalSequence = new ArrayList<>();
    } else {
      numericalSequence.add(2 * x);
    }
  }

  public boolean arrayListEmpty() {
    // NOTE: Your sample code can be reduced to this one-liner
    return numericalSequence.isEmpty();
  }
}

以下是上述代码中的一些缺陷:

  1. doSomething方法允许可为空(装箱的整数)值,因此可以在第一个NullPointerException语句中引起if
  2. numericalSequence成员不是最终成员,因此将其设置为null的代码在doSomething方法内部有效
  3. arrayListIsEmpty方法不会检查numericalSequence是否为空
  4. 如果我想测试arrayListIsEmpty为null或具有null元素时numericalSequence的行为,除非您知道如何使类达到该状态,否则很难这样做。

如果该类被重写为以下内容:

class MyClass {
  private final List<Integer> numericalSequence;

  public MyClass() {
    this(new ArrayList<>());
  }

  // Should be made public only if the classes that use this one needs to
  // initialize this instance with the sequence. Make this package-private
  // otherwise.
  public MyClass(List<Integer> sequence) {
    this.numericalSequence = sequence;
  }

  public void doSomething(int x) {
    if (x < 0) {
      // COMPILE ERROR: Cannot assign to a final member
      // numericalSequence = new ArrayList<>();
      numericalSequence.clear();
    } else {
      numericalSequence.add(2 * x);
    }
  }

  public boolean arrayListEmpty() {
    return numericalSequence == null || numericalSequence.isEmpty();
  }
}

关于上述结构的几点注意事项:

  1. 有两个构造函数;默认调用一个以整数列表为序列的整数,以便它重用两者都需要共享的任何逻辑。此示例中没有逻辑,但是希望您很快会遇到。
  2. doSomething()方法不接受Integer的值,而是int的值,该值可确保x永远不会null(Java数值基元类型不能是null)。这也意味着numericalSequence不能通过doSomething()包含空值。
  3. 由于numericalSequence可以从此类之外进行初始化,因此arrayListEmpty()方法可确保检查numericalSequence是否为null为空。

现在您可以像这样编写测试用例:

@Test
public void arrayListEmpty_WhenListIsNull() {
  MyClass test = MyClass(null);
  assertTrue(test.arrayListEmpty());
}

@Test
public void arrayListEmpty_WhenListIsEmpty() {
  MyClass test = MyClass();
  assertTrue(test.arrayListEmpty());
}

@Test
public void arrayListEmpty_WhenListHasOnlyOneNonNullElement() {
  List<Integer> sequence = new ArrayList<>();
  sequence.add(0);
  MyClass test = new MyClass(sequence);
  assertFalse(test.arrayListEmpty());
}

@Test
public void arrayListEmpty_WhenListHasOnlyOneNullElement() {
  List<Integer> sequence = new ArrayList<>();
  sequence.add(null);
  MyClass test = new MyClass(sequence);
  assertFalse(test.arrayListEmpty());
}

由于doSomething()添加/清除了序列,因此在为doSomething()编写测试时,请确保调用并通过检查arrayListEmpty()的返回值来验证类的状态。

例如:

@Test
public void doSomething_WhenInputLessThanZero() {
  List<Integer> sequence = new ArrayList<>();
  sequence.add(0);
  MyClass test = new MyClass(sequence);
  test.doSomething(-1);
  assertTrue(test.arrayListEmpty());
}

我打算展示几件事:

  1. 将您的测试用例构造得紧凑而简洁
  2. 将您的课程设计为易于测试

希望这会有所帮助。