假设您有一个包含以下行的单元测试:
assertNotNull(someVal);
assertNotEmpty(someVal);
这显然检查了someVal不为null并且被填充了一些东西。
问题是,第一行是否必要并且是否对测试有所帮助?我们不应该只有第二行吗?如果它为空,它将抛出一个空指针异常,这仍然表示单元测试失败(但不是断言失败)。
在这种简单情况下,最佳实践是什么?
假设您有一个包含以下行的单元测试:
assertNotNull(someVal);
assertNotEmpty(someVal);
这显然检查了someVal不为null并且被填充了一些东西。
问题是,第一行是否必要并且是否对测试有所帮助?我们不应该只有第二行吗?如果它为空,它将抛出一个空指针异常,这仍然表示单元测试失败(但不是断言失败)。
在这种简单情况下,最佳实践是什么?
在测试执行过程中,出现NPE时不应该视为测试失败。相反,您应该断言其不为空并提供错误消息:
assertNotNull(someVal, "应提供一些具有描述性的消息,说明为何值不应为null");
这要看情况。假设您正在测试myFunc函数。如果myFunc在非异常情况下返回null,则检查结果既不为空也是正确的值,这样可以使您的测试更清晰。
但如果null是一个异常情况,那么检查它就像在测试中捕获RuntimeException一样。这只会让您的测试变得混乱并且模糊了您的意图。
在JUnit中,故障和错误有所不同。故障是预期的事情(使用assertXXX()
或fail()
进行显式测试),而错误通常是异常情况。请参见What's the difference between failure and error in JUnit?。
如果您调用
assertNotNull(someVal);
如果您说这个值不应该为空,并且您正在特别测试它。如果让NullPointerException发生,那么解释错误的人将不知道被测试的代码是否正确,或者您只是没有考虑所有情况。
这是意图的问题。正如其他人指出的那样,添加说明消息是一个好主意。
我不太喜欢使用assertNot()
,更普遍地说,不喜欢测试可能发生在SUT上的意外情况,更不要在每个测试中除了正常断言之外再测试它们。
我认为你只应该测试对象的正常状态。如果在某些情况下someVal
为空是正常的,则创建一个专用的测试方法来检查在该场景下它确实为空。为你的测试选择一个表达意图的名称,如someValShouldBeNullWhen...()
。对于空值或任何其他值也可以这样做。
通过查看测试异常消息,您可以看到意外情况发生在SUT上,而不是试图预测每个意外情况并将其塞入assertNots中。