Java 在JUnit测试中尝试catch

Java 在JUnit测试中尝试catch,java,unit-testing,junit,try-catch,Java,Unit Testing,Junit,Try Catch,我正在为一个已经存在很长时间的应用程序编写单元测试。我需要测试的一些方法如下所示: public void someMethod() throws Exception { //do something } @Test public void someTest() throws Exception { someMethod(); } 如果我想测试这些方法,我必须在单元测试中编写如下内容: @Test public void someTest() { try {

我正在为一个已经存在很长时间的应用程序编写单元测试。我需要测试的一些方法如下所示:

public void someMethod() throws Exception { 
   //do something 
}
@Test
public void someTest() throws Exception {
     someMethod();
}
如果我想测试这些方法,我必须在单元测试中编写如下内容:

@Test
public void someTest() {
   try {
      someMethod();
   }
   catch (Exception e) {
      e.printStackTrace();
   }
}
这样做是一种好的做法吗?还是有其他方法来测试这些方法

我在互联网上做了一些研究,发现了一些带有
@Rule
注释和
@Test(expected=Exception.class)
的解决方案,但这不起作用(Eclipse一直将测试中的
someMethod()
行显示为错误)。 我不知道这些是否是好的解决方案,因为我对整个单元测试故事还很陌生


如果有一位对此非常了解的人能够帮助我,我将非常感谢。

因为
异常是一个选中的异常,您可以:

  • 必须捕获
    try…catch
    语句中的异常,或
  • 声明要在方法本身中引发的异常
您在上面所做的工作很好,但是我个人的偏好是声明要抛出的异常。这样,如果在测试运行期间抛出我不期望的异常,测试将失败

如果我们需要查看是否引发了特定异常,那么您可以选择使用
@Rule
或直接将值添加到
@Test
注释中

@Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
    // dodgy code here
}
在JUnit5中,您可以利用它来完成同样的事情。总的来说,我对它不太熟悉,因为在编辑时它还不是GA,但它似乎接受来自JUnit5的
可执行文件

@Test
public void someTest() {
    assertThrows(FileNotFoundException.class, () ->
         { dodgyService.breakableMethod() };
}
如果不应发生异常,则可以执行以下操作。另一种方法是在签名中抛出异常,如下所示:

public void someMethod() throws Exception { 
   //do something 
}
@Test
public void someTest() throws Exception {
     someMethod();
}
区别在于,在一种情况下,测试将因断言异常而失败,而在另一种情况下,它将因测试崩溃而失败。(比如在代码中的某个地方,您得到了一个NPE,因此测试将失败)

您必须这样做的原因是,异常是已检查的异常。看

@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

}

不要在测试代码中捕获应用程序的异常。相反,声明它是向上扔的

因为,当JUnit的
TestRunner
发现抛出的异常时,它会自动将其记录为testcase的
错误

只有当您
testcase
期望该方法引发
异常时,您才应该使用
@Test(expected=Exception.class)
或捕获异常

在其他情况下,只要用

public void someTest() throws Exception {

您可以在测试方法签名中添加异常。然后,如果您正在测试是否抛出异常,则必须使用
@Test(expected=exception.class)
。在不必抛出异常的测试用例中,测试将成功通过

@Test
public void testCaseWhereExceptionWontBeThrown() throws Exception {
    someMethod(); //Test pass
}

@Test(expected = Exception.class)
public void testCaseWhereExceptionWillBeThrown() throws Exception {
    someMethod(); //Test pass
}

关于如何在Junit测试人员中处理异常,有两条主要规则:

  • 如果异常源于测试代码:

    • 如果它是预期的,则在
      Test
      注释的
      expected
      属性中声明它。或者,如果需要对异常对象本身进行进一步检查,则捕获它并忽略它。(在这种情况下,还必须在
      try
      块的末尾调用
      Assert.fail
      ,以指示未生成预期的异常)
    • 如果它不是预期的,则捕获它并执行Assert.fail。(先前对
      Exception.printStackTrace
      的调用也很有用)
  • 如果异常不是源于测试代码,或者对测试不感兴趣(例如,大多数IOException都是在网络级别生成的,甚至在测试完成之前),请在
    throws
    子句中重新显示它。

  • 为什么测试仪中会出现异常?提醒:您应该为测试代码上的每个可能结果编写一个测试方法(以实现较高的代码覆盖率):在您的情况下,一个方法必须成功返回,至少另一个方法必须产生异常。

    这是什么样的异常?是吗

  • 使用单元测试或测试中不会发生的流之类的操作的例外
  • 由于某种错误输入而可能发生的异常
  • 如果是1。我只想把它放在方法签名级别,因为try-catch除了仪式之外没有其他真正的用途

    @Test
    public void testFoo() throws Exception {
        // ...
    }
    
    如果是2。它变得有点复杂了。您需要问问自己,如果抛出异常,应该发生什么。测试失败了吗?这是预期的吗?这无关紧要吗?下面举例说明如何处理所有这些问题注意:我只使用了Exception,因为您使用了Exception。我希望它不是真的,因为如果有可能抛出除预期之外的其他异常,那么这些异常将非常不可靠。如果可能,不要使用
    异常
    ,使用更具体的内容(在junit和代码中)


    关于JUnit有三点:

    • 测试应该是精确的,它们的通过或失败应该完全基于测试输入是如何设置的

    • 测试应该将失败报告回框架中

    • 测试不应依赖于读取其输出

    你的例子在这三个方面都失败了。如果抛出或未抛出异常,测试仍然通过。如果抛出异常,JUnit永远不会发现它,也不能将其包含在测试结果中。知道出错的唯一方法是读取测试写入stdout的内容,这使得错误很容易被忽略。这不是编写测试的有用方法

    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...
    }