Java JUnit 测试抛出异常的错误形式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1836364/
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-12 23:08:39  来源:igfitidea点击:

Bad form for JUnit test to throw exception?

javaunit-testingtestingjunit

提问by Seth

I'm pretty new to JUnit, and I don't really know what best practices are for exceptions and exception handling.

我对 JUnit 很陌生,我真的不知道异常和异常处理的最佳实践是什么。

For example, let's say I'm writing tests for an IPAddress class. It has a constructor IPAddress(String addr) that will throw an InvalidIPAddressException if addr is null. As far as I can tell from googling around, the test for the null parameter will look like this.

例如,假设我正在为 IPAddress 类编写测试。它有一个构造函数 IPAddress(String addr),如果 addr 为 null,它将抛出 InvalidIPAddressException。据我通过谷歌搜索可以看出,空参数的测试将如下所示。

@Test
public void testNullParameter()
{
    try
    {
        IPAddress addr = new IPAddress(null);
        assertTrue(addr.getOctets() == null);
    }
    catch(InvalidIPAddressException e)
    {
        return;
    }

    fail("InvalidIPAddressException not thrown.");
}

In this case, try/catch makes sense because I know the exception is coming.

在这种情况下,try/catch 是有意义的,因为我知道异常即将到来。

But now if I want to write testValidIPAddress(), there's a couple of ways to do it:

但是现在如果我想编写 testValidIPAddress(),有几种方法可以做到:

Way #1:

方式#1:

@Test
public void testValidIPAddress() throws InvalidIPAddressException
{
    IPAddress addr = new IPAddress("127.0.0.1");
    byte[] octets = addr.getOctets();

    assertTrue(octets[0] == 127);
    assertTrue(octets[1] == 0);
    assertTrue(octets[2] == 0);
    assertTrue(octets[3] == 1);
}

Way #2:

方式#2:

@Test
public void testValidIPAddress()
{
    try
    {
        IPAddress addr = new IPAddress("127.0.0.1");
        byte[] octets = addr.getOctets();

        assertTrue(octets[0] == 127);
        assertTrue(octets[1] == 0);
        assertTrue(octets[2] == 0);
        assertTrue(octets[3] == 1);
    }
    catch (InvalidIPAddressException e)
    {
        fail("InvalidIPAddressException: " + e.getMessage());
    }
}

Is is standard practice to throw unexpected exceptions to JUnit or just deal with them yourself?

向 JUnit 抛出意外异常还是自己处理它们是标准做法吗?

Thanks for the help.

谢谢您的帮助。

采纳答案by Pascal Thivent

Actually, the old style of exception testingis to wrap a try block around the code that throws the exception and then add a fail()statement at the end of the try block. Something like this:

实际上,旧式的异常测试是在抛出异常的代码周围包裹一个 try 块,然后fail()在 try 块的末尾添加一条语句。像这样的东西:

public void testNullParameter() {
    try {
        IPAddress addr = new IPAddress(null);
        fail("InvalidIPAddressException not thrown.");
    } catch(InvalidIPAddressException e) {
        assertNotNull(e.getMessage());
    }
}

This isn't much different from what you wrote but:

这与您写的没有太大区别,但是:

  1. Your assertTrue(addr.getOctets() == null);is useless.
  2. The intend and the syntax are clearer IMO and thus easier to read.
  1. assertTrue(addr.getOctets() == null);的没用。
  2. IMO 的意图和语法更清晰,因此更易于阅读。

Still, this is a bit ugly. But this is where JUnit 4 comes to the rescue as exception testing is one of the biggest improvements in JUnit 4. With JUnit 4, you can now write your test like this:

尽管如此,这还是有点难看。但这正是 JUnit 4 的用武之地,因为异常测试是 JUnit 4 中最大的改进之一。使用 JUnit 4,您现在可以像这样编写测试:

@Test (expected=InvalidIPAddressException.class) 
public void testNullParameter() throws InvalidIPAddressException {
    IPAddress addr = new IPAddress(null);
}

Nice, isn't it?

不错,不是吗?

Now, regarding the real question, if I don't expect an exception to be thrown, I'd definitely go for way #1 (because it's less verbose) and let JUnit handle the exception and fail the test as expected.

现在,关于真正的问题,如果我不希望抛出异常,我肯定会选择#1(因为它不那么冗长)并让 JUnit 处理异常并按预期失败测试。

回答by digiarnie

For the null test you can simply do this:

对于空测试,您可以简单地执行以下操作:

public void testNullParameter() {
    try {
            IPAddress addr = new IPAddress(null);
            fail("InvalidIPAddressException not thrown.");
    }
    catch(InvalidIPAddressException e) { }
}

If the exception has a message, you could also check that message in the catch if you wish. E.g.

如果异常有一条消息,您也可以根据需要在 catch 中检查该消息。例如

String actual = e.getMessage();
assertEquals("Null is not a valid IP Address", actual);

For the valid test you don't need to catch the exception. A test will automatically fail if an exception is thrown and not caught. So way #1 would be all you need as it will fail and the stack trace will be available to you anyway for your viewing pleasure.

对于有效测试,您不需要捕获异常。如果异常被抛出但未被捕获,测试将自动失败。因此,#1 将是您所需要的全部方式,因为它会失败,并且无论如何您都可以使用堆栈跟踪以供您观看。

回答by pstanton

if i understand your question, the answer is either - personal preference.

如果我理解你的问题,答案是 - 个人喜好。

personally i throw my exceptions in tests. in my opinion a test failing by assertion is equivalent to a test failing by an uncaught exception. both show something that needs to be fixed.

我个人在测试中抛出我的异常。在我看来,因断言而失败的测试等同于因未捕获的异常而失败的测试。两者都显示了需要修复的东西。

the important thing to remember in testing is code coverage.

在测试中要记住的重要一点是代码覆盖率。

回答by Brian Agnew

For tests where I don't expect an exception, I don't bother to catch it. I let JUnit catch the exception (it does this reliably) and don't cater for it at all beyond declaring the throwscause (if required).

对于我不希望出现异常的测试,我不会费心去捕捉它。我让 JUnit 捕获异常(它可靠地执行此操作)并且除了声明throws原因(如果需要)之外根本不满足它。

I note re. your firstexample that you're not making use of the @expectedannotation viz.

我注意到重新。您没有使用注释即的第一个示例@expected

@Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
    int[] intArray = new int[10];

    int i = intArray[20]; // Should throw IndexOutOfBoundsException
  }

I use this for all tests that I'm testing for throwing exceptions. It's briefer than the equivalent catch/fail pattern that I had to use with Junit3.

我将它用于我正在测试抛出异常的所有测试。它比我必须在 Junit3 中使用的等效捕获/失败模式更简短。

回答by Yishai

In general way #1 is the way to go, there is no reason to call out a failure over an error - either way the test essentially failed.

一般来说,#1 是可行的方法,没有理由在错误上调用失败 - 无论哪种方式,测试基本上都失败了。

The only time way #2 makes sense if you need a good message of what went wrong, and just an exception won't give that to you. Then catching and failing can make sense to better announce the reason of the failure.

如果您需要关于出错的好消息,#2 的唯一时间方式是有意义的,而只是一个例外不会给您。然后捕获和失败可以更好地宣布失败的原因。

回答by Aravind Kannan

IMO it is better to handle the exception and show appropriate messaging from the test than throwing it from a test.

IMO 处理异常并从测试中显示适当的消息比从测试中抛出它更好。

回答by s106mo

Since JUnit 4.7 you have the possibility to use an ExpectedExceptionrule and you should use it. The rule gives you the possibility to define exactly the called method where the exception should be thrown in your test code. Moreover, you can easily match a string against the error message of the exception. In your case the code looks like this:

从 JUnit 4.7 开始,您可以使用ExpectedException规则,您应该使用它。该规则使您可以准确定义应在测试代码中抛出异常的被调用方法。此外,您可以轻松地将字符串与异常的错误消息进行匹配。在您的情况下,代码如下所示:

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Test
    public void test() {
        //working code here...
        expectedException.expect(InvalidIPAddressException.class);
        IPAddress addr = new IPAddress(null);
    }

UPDATE:In his book Practical Unit Testing with JUnit and MockitoTomek Kaczanowski argues against the use of ExpectedException, because the rule "breaks the arrange/act/assert [...] flow" of a Unit test (he suggests to use Catch Exception Libraryinstead). Although I can understand his argument, I think using the rule is fine if you do not want to introduce another 3rd-party library (using the rule is better than catching the exception "manually" anyway).

更新:在他的《使用 JUnit 和 MockitoTomek Kaczanowski 进行实用单元测试》一书中他反对使用 ExpectedException,因为该规则“破坏了单元测试的安排/执行/断言 [...] 流程”(他建议使用Catch Exception图书馆代替)。虽然我可以理解他的论点,但我认为如果您不想引入另一个 3rd 方库,则使用该规则是可以的(无论如何,使用该规则比“手动”捕获异常要好)。

回答by Venu b

Reg: Testing for Exceptions
I agree with "Pascal Thivent", ie use @Test (expected=InvalidIPAddressException.class)

Reg:异常测试
我同意“Pascal Thivent”,即使用@Test (expected=InvalidIPAddressException.class)



Reg: Testing for testValidIPAddress

注册:测试 testValidIPAddress

IPAddress addr = new IPAddress("127.0.0.1");
byte[] octets = addr.getOctets();

I would write a test like

我会写一个测试

class IPAddressTests
{

    [Test]
    public void getOctets_ForAValidIPAddress_ShouldReturnCorrectOctect()
    {
         // Test code here
    }

}

The point is when testinput is VALID ipAddress
The test must be on the public methods/capabilities on the class asserting that they are working as excepted

关键是当 testinput 是 VALID ipAddress
测试必须在类上的公共方法/功能上,断言它们作为例外工作