Java JUnit测试引发异常的错误形式?
我对JUnit非常陌生,我不知道异常和异常处理的最佳实践是什么 例如,假设我正在为一个IPAddress类编写测试。它有一个构造函数IPAddress(String addr),如果addr为null,它将抛出InvalidIPAddressException。从谷歌搜索中我可以看出,null参数的测试如下所示Java JUnit测试引发异常的错误形式?,java,unit-testing,testing,junit,Java,Unit Testing,Testing,Junit,我对JUnit非常陌生,我不知道异常和异常处理的最佳实践是什么 例如,假设我正在为一个IPAddress类编写测试。它有一个构造函数IPAddress(String addr),如果addr为null,它将抛出InvalidIPAddressException。从谷歌搜索中我可以看出,null参数的测试如下所示 @Test public void testNullParameter() { try { IPAddress addr = new IPAddress(
@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:
道路#2:
标准做法是向JUnit抛出意外异常,还是自己处理
感谢您的帮助。对于空测试,您只需执行以下操作:
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将是您所需要的,因为它将失败,堆栈跟踪将为您提供查看乐趣。如果我理解您的问题,答案是-个人偏好 就个人而言,我在测试中抛出异常。在我看来,断言导致的测试失败等同于未捕获异常导致的测试失败。两者都显示了一些需要修复的问题
在测试中要记住的重要一点是代码覆盖率。对于我不希望出现异常的测试,我不会费心捕捉它。我让JUnit捕获异常(它可以可靠地执行此操作),并且除了声明
抛出原因(如果需要)之外,根本不满足它
我注意到了你。您没有使用@expected
注释viz的第一个示例
@Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
int[] intArray = new int[10];
int i = intArray[20]; // Should throw IndexOutOfBoundsException
}
我在测试抛出异常的所有测试中都使用这个。它比我必须在Junit3中使用的等效catch/fail模式更简单。实际上,异常测试的旧式方法是在抛出异常的代码周围包装一个try块,然后在try块的末尾添加一个fail()
语句。大概是这样的:
public void testNullParameter() {
try {
IPAddress addr = new IPAddress(null);
fail("InvalidIPAddressException not thrown.");
} catch(InvalidIPAddressException e) {
assertNotNull(e.getMessage());
}
}
@Test (expected=InvalidIPAddressException.class)
public void testNullParameter() throws InvalidIPAddressException {
IPAddress addr = new IPAddress(null);
}
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void test() {
//working code here...
expectedException.expect(InvalidIPAddressException.class);
IPAddress addr = new IPAddress(null);
}
这和你写的没什么不同,但是:
您的assertTrue(addr.getOctets()==null)代码>是无用的
在我看来,意图和语法更清晰,因此更容易阅读
不过,这有点难看。但这正是JUnit4得以拯救的地方,因为异常测试是JUnit4最大的改进之一。使用JUnit 4,您现在可以这样编写测试:
public void testNullParameter() {
try {
IPAddress addr = new IPAddress(null);
fail("InvalidIPAddressException not thrown.");
} catch(InvalidIPAddressException e) {
assertNotNull(e.getMessage());
}
}
@Test (expected=InvalidIPAddressException.class)
public void testNullParameter() throws InvalidIPAddressException {
IPAddress addr = new IPAddress(null);
}
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void test() {
//working code here...
expectedException.expect(InvalidIPAddressException.class);
IPAddress addr = new IPAddress(null);
}
很好,不是吗
现在,关于真正的问题,如果我不希望抛出异常,我肯定会选择方法1(因为它不那么冗长),让JUnit处理异常并按预期通过测试。一般来说,方法是1,没有理由为错误调用失败-无论哪种方法,测试基本上都失败了
如果你需要一个关于出错原因的好消息,那么唯一的时间方法#2是有意义的,而仅仅是一个例外不会给你这个信息。然后,捕获和失败可以更好地宣布失败的原因。在我看来,处理异常并从测试中显示适当的消息比从测试中抛出消息更好。因为JUnit 4.7,您可以使用规则,您应该使用它。该规则使您能够准确地定义被调用的方法,在该方法中,异常应该在测试代码中抛出。此外,您可以轻松地将字符串与异常的错误消息进行匹配。在您的情况下,代码如下所示:
public void testNullParameter() {
try {
IPAddress addr = new IPAddress(null);
fail("InvalidIPAddressException not thrown.");
} catch(InvalidIPAddressException e) {
assertNotNull(e.getMessage());
}
}
@Test (expected=InvalidIPAddressException.class)
public void testNullParameter() throws InvalidIPAddressException {
IPAddress addr = new IPAddress(null);
}
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void test() {
//working code here...
expectedException.expect(InvalidIPAddressException.class);
IPAddress addr = new IPAddress(null);
}
更新:在他的书中,Tomek Kaczanowski反对使用ExpectedException,因为该规则“破坏了单元测试的排列/动作/断言[…]流程”(他建议改为使用)。虽然我能理解他的论点,但如果您不想引入另一个第三方库,我认为使用规则是可以的(无论如何,使用规则比“手动”捕获异常要好)。Reg:测试异常
我同意“Pascal Thivent”,即使用@Test(预期=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是有效的IP地址
测试必须在类上的公共方法/功能上进行,该类声明它们作为例外工作我实际尝试了testNullParameter()的@test(expected=InvalidIPAddressException.class),并且测试在eclipse中返回了错误。你有没有遇到过这种情况?嗯,我刚刚试过JUnit4和Eclipse,测试运行得很好。但是,我忘记了答案中的throws子句,如果InvalidIPAddressException
是选中的异常,则该子句是必需的。我相应地修改了我的答案。这有帮助吗?没有。不过我可能会发布一个不同的问题。感谢您的帮助。@Test(expected=…)表单实际上可能比显式的try/catch更糟糕,例如,如果测试的“setup”部分可以抛出预期的异常。您将丢失错误定位,即使已执行的方法停止抛出正确的异常,您的测试也可以保持绿色。如果在上下文中这是一件有趣的事情,那么try-catch方法将允许您测试抛出的异常的特征。此解决方案为测试添加了更多的样板文件,几乎没有任何好处。让JUnit通过将有问题的测试标记为错误来处理意外异常;如果测试的成功结果取决于引发特定异常的测试主题,请使用测试注释的“expected”属性,或使用ExpectedException JUnit规则。测试应设计为多次运行。测试的最大优点是当它们被自动化时,例如:每次您将代码签入源代码管理时,测试都可以运行。所以这里有很多