繁体   English   中英

如何在junit4 Java中测试多行代码是否引发异常

[英]How to test if multiple lines of code throw an exception in junit4 Java

我正在为类的方法add(T elem, int index)写一个否定测试。 如果index < 0 || index > size || elem == null则该方法应引发IllegalArgumentException index < 0 || index > size || elem == null index < 0 || index > size || elem == null 我的测试看起来像这样:

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

@Test(expected = IllegalArgumentException.class) 
public void addNegTest() {
    l0.add(42, 10);  // index > size 
    l0.add(42, -1);  // index < 0
    l0.add(null, 2); // elem == null
}

该测试变为绿色,但是我发现这三行代码中只有1个抛出一个异常即可使测试变为绿色。 因此,如果我向这样的代码中添加1行,测试仍然会变为绿色。

@Test(expected = IllegalArgumentException.class) 
public void addNegTest() {
    l0.add(42, 10);  // index > size 
    l0.add(42, -1);  // index < 0
    l0.add(null, 2); // elem == null
    l0.add(42, 0);   // this is perfectly fine 
}

那么,如何确保测试测试每一行是否引发一个异常而不仅仅是一个异常?

预期的异常是整个测试方法执行的范围,无论是否有其他语句不抛出异常。
因此,您应该根据可能的情况创建一种测试方法。

@Test(expected = IllegalArgumentException.class) 
public void add_with_index_greater_than_size() {
    l0.add(42, 10);  // index > size 
}  

@Test(expected = IllegalArgumentException.class) 
public void add_with_index_less_than_zero() {
    l0.add(42, -1);  
}  

@Test(expected = IllegalArgumentException.class) 
public void add_with_null_arg() {
    l0.add(null, 10); 
}  

@Test
public void add() {
    l0.add(42, 10);  
    Assert.assertEquals(42, l0.get(10));
}  

尽管仍然可以使用一个测试方法,但try/catch语句的数量与失败的场景一样多,如SilverNak答案所示,但出于可读性原因,我不建议您使用它。

请注意,除了您的情况外,在自己的方法中指定每个不同的场景是一个好习惯,因为它可以使测试更具可读性,并且由于其责任更加明确和明确,也使得更容易/更容易纠正失败的测试。


JUnit 5改进

请注意,使用最新发行的JUnit版本,您可以使用相同的方法收集一些常见情况,而不会降低代码的可读性。
您可以收集传递给诸如以下错误索引的无效案例:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
...
@Test
public void add_with_index_less_than_zero_or_greater_than_size() {
    Assertions.assertThrows(IllegalArgumentException.class, 
                             () -> l0.add(42, 10));
    Assertions.assertThrows(IllegalArgumentException.class, 
                             () -> l0.add(42, -1));
}  

但我会将其保留在单独的方法中:

import  org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
...
@Test
public void add_with_null_arg() {
    Assertions.assertThrows(IllegalArgumentException.class, 
                             () -> l0.add(null, 10));
}  

通过编写四种不同的测试方法:

@Test(expected = IllegalArgumentException.class) 
public void addNegTest_indexTooLarge() {
    l0.add(42, 10);  // index > size 
}

@Test(expected = IllegalArgumentException.class) 
public void addNegTest_negativeIndex() {
    l0.add(42, -1);  // index < 0
}

@Test(expected = IllegalArgumentException.class) 
public void addNegTest_nullElement() {
    l0.add(null, 2); // elem == null
}

@Test
public void addNegTest_ok() {
    l0.add(42, 0);   // this is perfectly fine 
}

如果使用JaCoCo之类的插件,则可以从视觉上确认是否覆盖了所有可能的路径。

异常将终止当前执行的方法,直到捕获到异常为止。 因此,您有两种可能性:

每种测试一种方法

您可以为每种情况都应抛出异常的情况编写一种方法:

@Test(expected = IllegalArgumentException.class) 
public void addIndexGreaterThanSize() {
    l0.add(42, 10);  // index > size 
}

@Test(expected = IllegalArgumentException.class) 
public void addIndexNegative() {
    l0.add(42, -1);  // index < 0
}

@Test(expected = IllegalArgumentException.class) 
public void addElementNull() {
    l0.add(null, 2); // elem == null
}

自己捕获异常

您也可以自己捕获所有异常,如果未引发异常,则测试失败。 使用此方法时,可以验证异常的其他属性(例如,消息)。

@Test
public void addNegTest() {
    try {
        l0.add(42, 10);  // index > size 
        fail();
    } catch (IllegalArgumentException e) {}
    try {
        l0.add(42, -1);  // index < 0
        fail();
    } catch (IllegalArgumentException e) {}
    try {
        l0.add(null, 2); // elem == null
        fail();
    } catch (IllegalArgumentException e) {}
}

如果确实要测试引发的异常的其他属性,则可以选择第二种方法。 否则,我建议第一种选择,因为它更易于理解,编写自己的代码更少。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM