我为已经存在了很长时间的应用程序编写单元测试。我需要测试的一些方法是这样构建的:
target = "_self"
如果我想测试这些方法,我必须在单元测试中编写类似的东西:
public void someMethod() throws Exception {
//do something
}
这样做是一种好习惯吗?或者还有其他方法来测试这些方法吗?
我在互联网上进行了一些研究,我发现了一些带有@Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
e.printStackTrace();
}
}
注释和@Rule
的解决方案,但这些解决方案不起作用(Eclipse不断显示@Test(expected=Exception.class)
行在测试中作为错误)。
我不知道这些是不是很好的解决方案,因为我对整个单元测试故事都很陌生。
如果对此有很多了解的人可以帮助我,我会非常感激。
答案 0 :(得分:63)
由于Exception
是已检查的例外,您可以:
try...catch
声明或你有什么工作正常,但我个人的偏好是声明抛出异常。这样,如果在测试运行期间抛出了我不期望的异常,则测试将失败。
@Test
public void someTest() throws Exception {
// dodgy code here
}
如果我们需要查看是否抛出了特定异常,那么您可以选择使用@Rule
或直接将值添加到@Test
注释。
@Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
// dodgy code here
}
在JUnit 5中,您可以利用Assertions.expectThrows
来完成同样的事情。我对这个整体不太熟悉,因为它在编辑时还不是GA,但似乎接受来自JUnit 5的Executable
。
@Test
public void someTest() {
assertThrows(FileNotFoundException.class, () ->
{ dodgyService.breakableMethod() };
}
答案 1 :(得分:22)
@Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
Assert.fail("Exception " + e);
}
}
如果不应发生异常,您可以做什么。另一种方法是在签名中抛出异常,如下所示:
@Test
public void someTest() throws Exception {
someMethod();
}
不同之处在于,在一种情况下,测试将因断言异常而失败,而在另一种情况下,由于测试崩溃,它将失败。 (就像代码中的某个地方你得到了一个NPE,测试就是因为这个)
您必须这样做的原因是因为Exception是一个已检查的异常。见Checked versus unchecked exception
@Test(expected = Exception.class)用于测试,它想测试是否会抛出异常。
@Test(expected=ArrayIndexOutOfBounds.class)
public void testIndex() {
int[] array = new int[0];
int var = array[0]; //exception will be thrown here, but test will be green, because we expect this exception
}
答案 2 :(得分:7)
请勿在测试代码中捕获应用程序的异常。相反,声明它被向上抛出。
因为,当JUnit的TestRunner
发现抛出异常时,它会自动将其记录为测试用例的error
。
仅当您testcase
期望该方法应该抛出Exception
时,您应该使用@Test(expected=Exception.class)
或捕获异常。
在其他情况下,只需将其向上抛出,
public void someTest() throws Exception {
答案 3 :(得分:2)
关于JUnit的三点:
测试应该是准确的,它们应该根据测试输入的设置方式明确地通过或失败。
测试应该将失败报告回框架。
测试不应该依赖于读取输出。
你的例子在所有三个方面都失败了。如果抛出异常,测试仍会通过。如果抛出异常,JUnit永远不会发现它并且不能将它包含在测试结果中。知道错误的唯一方法是读取测试写入stdout的内容,这使得错误太容易被忽略。这不是编写测试的有用方法。
JUnit旨在使正确的事情变得简单,并为开发人员提供有用的反馈。如果从测试方法抛出异常,它将被框架捕获。如果测试使用异常进行注释,指示异常是预期的,则框架将测试标记为已通过。否则,框架将无法通过测试并记录堆栈跟踪以进行报告。该框架报告断言失败以及发生了哪些意外异常,以便每个人都知道测试是否有效。
如果您希望测试成功而不抛出异常,那么如果测试中的任何内容都可以抛出已检查的异常,请将throws Exception
添加到测试方法签名中。将throws
添加到签名并不表示方法必须抛出任何东西,它只是让任何发生的异常被抛出,以便测试框架可以捕获它们。
在测试中实际捕获异常的唯一实例是您要测试有关异常的断言;例如,您可以测试异常上的消息是否符合预期,或者异常是否设置了原因。在这种情况下,您可以在try-block的末尾添加Assert.fail()
,这样不会抛出异常会导致测试失败。
首先编写测试时,请使其失败。这样你就可以向自己证明你知道测试是做什么的,并且你确认,当失败时,你会意识到它。
答案 4 :(得分:0)
它有什么例外?是吗
如果它是1.我会把它放在方法签名级别,因为try-catch除了仪式之外没有任何其他用途。
@Test
public void testFoo() throws Exception {
// ...
}
如果是2.它变得有点复杂。如果抛出异常,你需要问问自己应该发生什么。测试应该失败吗?这是预期的吗?这无关紧要吗?以下示例如何处理所有这些。 当心:我只使用了Exception,因为你做到了。我希望它真的不是因为如果某些其他异常可能被抛出而不是预期那么这些将是非常不可靠的。如果可能,请不要使用Exception
,请使用更具体的内容(在junit 和代码中)。
// The below code assumes you've imported the org.junit.Assert class.
@Test
public void thisShouldFailIfExceptionCaught() {
//Given...
try {
// When...
} catch (Exception e) {
Assert.fail();
}
// Then...
}
@Test
public void thisShouldPassOnlyIfTheExceptionIsCaught() {
//Given...
try {
// When...
Assert.fail();
} catch (Exception expected) {}
// No "then" needed, the fact that it didn't fail is enough.
}
@Test
public void irrelevantExceptionThatCouldBeThrown() {
//Given...
try {
// When...
} catch (Exception e) {}
// Then...
}