首页 文章

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

提问于
浏览
56

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

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

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

    fail("InvalidIPAddressException not thrown.");
}

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

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

方式#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);
}

方式#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());
    }
}

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

谢谢您的帮助 .

8 回答

  • -2

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

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

    这和你写的没什么不同,但是:

    • 你的 assertTrue(addr.getOctets() == null); 没用了 .

    • 意图和语法更清晰IMO,因此更容易阅读 .

    不过,这有点难看 . 但这就是JUnit 4拯救的地方,因为异常测试是JUnit 4中最大的改进之一 . 使用JUnit 4,您现在可以像这样编写测试:

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

    不错,不是吗?

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

  • 0

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

    我个人在测试中抛出异常 . 在我看来,断言失败的测试等同于未被捕获的异常失败的测试 . 两者都表明需要修复的东西 .

    在测试中要记住的重要事项是代码覆盖率 .

  • 10

    注册:测试例外情况
    我同意"Pascal Thivent",即使用 @Test (expected=InvalidIPAddressException.class)


    注册:测试 testValidIPAddress

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

    我会写一个类似的测试

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

    关键是testInput是VALID ipAddress
    测试必须在类的公共方法/功能上声明它们作为例外工作

  • 0

    对于那些我不愿意接受它的测试 . 我让JUnit捕获异常(它可靠地执行此操作)并且除了声明 throws 原因(如果需要)之外根本不满足它 .

    我注意到了 . 你的第一个例子是你没有使用 @expected 注释即 .

    @Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
        int[] intArray = new int[10];
    
        int i = intArray[20]; // Should throw IndexOutOfBoundsException
      }
    

    我将此用于我正在测试抛出异常的所有测试 . 它比我必须与Junit3一起使用的等效捕获/失败模式更简洁 .

  • 0

    IMO最好处理异常并从测试中显示适当的消息,而不是从测试中抛出它 .

  • 9

    通常情况下,#1是要走的路,没有理由在错误中调出故障 - 无论哪种方式,测试基本上都失败了 .

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

  • 90

    从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: 在他的书Practical Unit Testing with JUnit and Mockito中,Tomek Kaczanowski反对使用ExpectedException,因为单元测试的规则"breaks the arrange/act/assert [...] flow"(他建议使用Catch Exception Library代替) . 虽然我可以理解他的论点,但我认为如果你不想引入另一个第三方库,使用该规则就好了(使用规则比捕获异常"manually"更好) .

  • 0

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

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

    如果异常有消息,您还可以根据需要在catch中检查该消息 . 例如 .

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

    对于有效测试,您不需要捕获异常 . 如果抛出异常而未捕获异常,则测试将自动失败 . 所以#1的方式就是你所需要的,因为它会失败,无论如何你都可以使用堆栈跟踪来获得观赏乐趣 .

相关问题