Java 在 JUnit 测试中尝试 catch

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31423643/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:06:25  来源:igfitidea点击:

Try catch in a JUnit test

javaunit-testingjunittry-catch

提问by Nelsch

I'm writing unit tests for an application that already exists for a long time. Some of the methods I need to test are build like this:

我正在为已经存在很长时间的应用程序编写单元测试。我需要测试的一些方法是这样构建的:

public void someMethod() throws Exception { 
   //do something 
}

If I want to test these methods I have to write something like this in my unit test:

如果我想测试这些方法,我必须在我的单元测试中写这样的东西:

@Test
public void someTest() {
   try {
      someMethod();
   }
   catch (Exception e) {
      e.printStackTrace();
   }
}

Is it a good practice to do this? Or is there an other way to test these methods?

这样做是一个好习惯吗?或者有其他方法来测试这些方法吗?

I did some research on the internet and I found a few solutions with the @Ruleannotation and @Test(expected=Exception.class), but that's not working (Eclipse keeps showing the someMethod()line in the test as wrong). I don't know if these are good solutions, because I'm pretty new to the whole unit testing story.

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

If someone who knows a lot about this could help me out, I would be really thankful.

如果有对这方面了解很多的人可以帮助我,我将不胜感激。

采纳答案by Makoto

Since Exceptionis a checked exception, you either:

由于Exception是受检异常,您可以:

  • Have to catch the exception in a try...catchstatement, or
  • Declare the exception to be thrown in the method itself.
  • 必须在try...catch语句中捕获异常,或
  • 在方法本身中声明要抛出的异常。

What you have up there works fine, but my personal preference is to declare the exception to be thrown. This way, if an exception I'm not expecting is thrown during the run of the test, the test will fail.

你在那里的工作正常,但我个人的偏好是声明要抛出的异常。这样,如果在测试运行期间抛出我不期望的异常,则测试将失败

@Test
public void someTest() throws Exception {
    // dodgy code here
}

If we need to see if a specific exception is thrown, then you have the option of using @Ruleor adding the value to the @Testannotation directly.

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

@Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
    // dodgy code here
}

In JUnit 5, you can leverage Assertions.assertThrowsto accomplish the same thing. I'm less familiar with this overall since it's not yet GA at the time of editing, but it appears to accept an Executablecoming from JUnit 5.

在 JUnit 5 中,您可以利用Assertions.assertThrows来完成同样的事情。我对这个整体不太熟悉,因为它在编辑时还不是 GA,但它似乎接受Executable来自 JUnit 5 的消息。

@Test
public void someTest() {
    assertThrows(FileNotFoundException.class, () ->
         { dodgyService.breakableMethod() };
}

回答by morpheus05

@Test
public void someTest() {
   try {
     someMethod();
   }
   catch (Exception e) {
     Assert.fail("Exception " + e);
   }
}

Is what you can do, if the exception should not occur. An alternative would be to throw the exception in the signature like this:

如果异常不应该发生,你可以做什么。另一种方法是在签名中抛出异常,如下所示:

@Test
public void someTest() throws Exception {
     someMethod();
}

The difference is, that in one case the test will fail with an assertion exception and in the other case it will fail because the test crashed. (like somewhere in your code you get a NPE and the test will because of that)

不同之处在于,在一种情况下,测试将因断言异常而失败,而在另一种情况下,由于测试崩溃而失败。(就像在您的代码中的某个地方,您会获得 NPE,因此测试将如此)

The reason you have to do this, is because Exception is a checked exception. See Checked versus unchecked exception

您必须这样做的原因是因为 Exception 是一个已检查的异常。请参阅已检查与未检查异常

The @Test(expected=Exception.class) is for tests, that want to test that the exception will be thrown.

@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

}

回答by Codebender

Do not catch your application's exception in your test code. Instead, declare it to be thrown upwards.

不要在测试代码中捕获应用程序的异常。相反,将其声明为向上抛出。

Because, when JUnit's TestRunnerfinds an exception thrown, it will automatically log it as an errorfor the testcase.

因为,当 JUnitTestRunner发现抛出的异常时,它会自动将其记录error为测试用例。

Only if you testcaseexpects that the method should thrown an Exceptionyou should use @Test(expected=Exception.class)or catch the exception.

只有当您testcase期望该方法应该抛出一个Exception您才应该使用@Test(expected=Exception.class)或捕获异常。

In other cases, just throw it upwards with,

在其他情况下,只需将其向上扔,

public void someTest() throws Exception {

回答by Héctor

You can add exception in test method signature. Then, if you are testing whether exception is thrown, you have to use @Test(expected=Exception.class). In the test cases where exception has not to be thrown, test will pass successfully.

您可以在测试方法签名中添加异常。然后,如果您正在测试是否抛出异常,则必须使用@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
}

回答by Little Santi

There are two main rules on how to process exceptions at Junit testers:

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

  1. If the exception was originated into the tested code:

    • If it was expected, declare it in the expectedattribute of the Testannotation. Or, if further checks should be done on the exception object itself, catch it and ignore it. (In this case, there must be also a call to Assert.failat the end of the tryblock, to indicate that the expected exception was not produced).
    • If it was not expected, catch it and execute Assert.fail. (A previous call to Exception.printStackTraceis also useful).
  2. If the exception was not originated into the tested code or it is not interesting to the test (for example, most of the IOExceptions are produced at network level, before the test could even be completed), rethrow it at the throwsclause.

  1. 如果异常起源于测试代码:

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

Why you should expect an exception in the tester? Remind: You should code one test method for every possible result on the tested code(in order to achieve a high code coverage): In your case, one method that must return successfully, and at least another one that must produce an Exception.

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

回答by Captain Man

What kind of exception is it? Is it

什么样的例外?是吗

  1. an exception from doing something like using streams that won't happen in your unit test or
  2. an exception that can happen because of some kind of bad input?
  1. 使用不会在单元测试中发生的流之类的操作的例外,或者
  2. 由于某种错误输入而可能发生的异常?

If it's 1. I would just put it at the method signature level because a try-catch is serving no real purpose other than ceremony.

如果是 1。我会把它放在方法签名级别,因为 try-catch 除了仪式之外没有任何真正的目的。

@Test
public void testFoo() throws Exception {
    // ...
}

If it's 2. it becomes a little more complicated. You need to ask yourself what should be happening if the Exception is thrown. Should the test fail? Is it expected? Is it irrelevant? Examples below of how to handle all of these. BEWARE:I only used Exception because you did. I hope it really isn't though because if it's possible for some otherexception to be thrown other than the expected then these will be very wonky. If possible don't use Exception, use something more specific (in the junit andcode).

如果是 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...
}

回答by Nathan Hughes

Three points about JUnit:

关于JUnit的三点:

  • Tests should be precise, they should pass or fail unambiguously based solely on how the test inputs are set up.

  • Tests should have failures reported back into the framework.

  • Tests should not rely on having their output read.

  • 测试应该是精确的,它们应该完全根据测试输入的设置方式明确地通过或失败。

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

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

Your example fails on all three counts. If an exception gets thrown or not, the test still passes. If an exception is thrown JUnit never finds out about it and can't include it in the test results. The only way to know something went wrong is to read what the test writes to stdout, which makes errors too easy to ignore. This is not a useful way to write tests.

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

JUnit was designed to make doing the right thing easy and to give developers useful feedback. If an exception gets thrown from a test method, it gets caught by the framework. If the test was annotated with an exception indicating that exception is expected, then the framework marks the test as passing. Otherwise the framework fails the test and records the stacktrace for reporting. The framework reports what assertions fail and what unexpected exceptions occurred so that everybody knows if the tests worked or not.

JUnit 旨在使做正确的事情变得容易,并为开发人员提供有用的反馈。如果测试方法抛出异常,它会被框架捕获。如果测试用异常进行注释,指示预期异常,则框架将测试标记为通过。否则,框架无法通过测试并记录堆栈跟踪以进行报告。该框架报告哪些断言失败以及发生了哪些意外异常,以便每个人都知道测试是否有效。

If you expect a test to succeed without throwing an exception, then if anything in the test can throw a checked exception, add throws Exceptionto the test method signature. Adding the throwsto the signature doesn't say the method has tothrow anything, it just lets any exceptions that happen to occur get thrown so that the test framework can catch them.

如果您希望测试成功而不会抛出异常,那么如果测试中的任何内容都可以抛出已检查的异常,请添加throws Exception到测试方法签名中。添加throws到签名中并没有说明该方法必须抛出任何东西,它只是让任何碰巧发生的异常都被抛出,以便测试框架可以捕获它们。

The only instance where you would actually catch the exception in the test is where you want to test assertions about the exception; for instance, you could test that the message on the exception is what you expect, or if the exception has a cause set on it. In that case you would add Assert.fail()at the end of the try-block so that not having an exception thrown will cause the test to fail.

在测试中实际捕获异常的唯一实例是您想要测试有关异常的断言的地方;例如,您可以测试异常消息是否符合您的预期,或者异常是否设置了原因。在这种情况下,您将Assert.fail()在 try 块的末尾添加,以便不抛出异常将导致测试失败。

When you write a test at first, make it fail. That way you prove to yourself that you know what the test is doing, and you confirm that, when there is a failure, you will be made aware of it.

一开始写测试时,让它失败。这样你就可以向自己证明你知道测试在做什么,并且你确认,当出现失败时,你会意识到它。