我正在为我们的主要产品编写单元测试并且有一个问题:如何区分
- 失败的测试是因为他们测试的东西出错了(例如发现了一个错误并且它是一个非回归测试)
- 由于测试的另一个意外部分失败而失败的测试(因为测试错误或出现未知错误)
对于第一个,我们肯定有 jUnit Assert 框架,但是对于第二个我们有什么?
示例:我的单元测试正在测试 c() 不会抛出 MyException,但要执行 c(),我需要先执行 a(),然后执行 b(),两者都可以抛出 MyException(),所以我会写:
@Test
public void testC() {
a();
Object forC = b();
try {
c(forC);
} catch (MyException e) {
Assert.fail("....");
}
}
但接下来我需要处理可能由 a 或 b 抛出的 MyException,还要处理 forC 不应该为 null 的事实。执行此操作的最佳方法是什么?
- 捕获由 a 或 b 抛出的 MyException 和 Assert.fail,但 a 和 b 未通过此测试进行测试,因此对我而言,当它们失败时不应将它们标记为测试失败。也许他们稍后会失败,因为此时我们应该做 b();a() 而不是 a();b();。
- 让 testC 抛出 MyException,这样测试就会失败并显示“MyException”,但这是一种误导,因为 MyException 不会告诉测试写错了。然后所有测试都将失败,每个测试都有自己的异常。在这种情况下,如果 forC 为 null,我还需要抛出 NullPointerException 之类的东西,这也没有语义。
- 捕获 a 和 b 抛出的 MyException 并将其包装成一个异常,告知测试可能有误,例如 TestCorruptedException。但是我在 jUnit 中找不到这样的异常,所以它们不会被 jUnit 识别(这对我来说没问题)。我还需要从我所有的单元测试中知道这个异常,这些单元测试当然分为多个模块、项目等等……所以这是可行的,但会增加依赖性。
您将如何解决这个问题?我可能会选择第二个,但如上所述我对此并不满意。
最佳答案
单元测试的基石是测试所需的最少代码量,否则它可能会落入您正在寻找端到端功能的集成测试空间。
如果你能证明 a()
可以在它自己的测试类中创建和测试,并且 b()
也可以在它自己的测试类中创建和测试测试类,那么您上面的测试可以忽略 a()
和 b()
的测试,而是使用不会失败的已知值。这通常通过使用 mock objects 来满足。 .
通过将 a() 和 b() 创建为模拟对象,c()
可以单独进行测试。如果您发现无法在隔离 a() 和 b() 的情况下测试 c(),那么这表明您的代码需要更改,以便分离关注点。这通常由 injecting the dependany 满足a() 和 b() 转化为 c()。
这篇文章在 when to use mock objects in unit testing可能有助于进一步阐明该主题。
关于java - 损坏的单元测试的语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11474063/