Junit中有好几种测试异常的方法。就像我在
前面几篇文章中写道的那样,我比较喜欢使用org.junit.rules.ExpectedException规则。一般来说,ExpectedException规则是org.junit.Before, org.junit.After, org.junit.BeforeClass,或者org.junit.AfterClass注解的一种替代方式 ,但是它们的功能更为强大,也更容易在多个工程间或者不同类中进行共享。本文中我会介绍下org.junit.rules.ExpectedException规则的一些高级用法。
验证异常信息
标准的JUnit的org.junit.Test注解提供了一个expected属性,你可以用它来指定一个Throwble类型,如果方法调用中抛出了这个异常,这条测试用例就算通过了。很多情况下有它就足够了,不过如果你想验证下异常的信息——你就得另寻出路了。使用ExpectedException来实现这个非常简单:
public class ExpectedExceptionsTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void verifiesTypeAndMessage() {
thrown.expect(RuntimeException.class);
thrown.expectMessage("Runtime exception occurred");
throw new RuntimeException("Runtime exception occurred");
}
}
在这段代码中,我们期望抛出的异常中包含指定的信息。和只匹配类型相比,这样做更安全。为什么?我们假设我们有这么个ExceptionThrower:
class ExceptionsThrower {
void throwRuntimeException(int i) {
if (i <= 0) {
throw new RuntimeException("Illegal argument: i must be <= 0");
}
throw new RuntimeException("Runtime exception occurred");
}
}
可以看到,抛出的两个异常都是RuntimeException,因此如果我们不检查异常信息的话,我们无法百分百确定方法抛出的异常到底是哪个。那么下面这个测试用例就会通过了:
@Test
public void runtimeExceptionOccurs() {
thrown.expect(RuntimeException.class);
// opposite to expected
exceptionsThrower.throwRuntimeException(0);
}
@Test
public void illegalArgumentExceptionOccurs() {
thrown.expect(RuntimeException.class);
// opposite to expected
exceptionsThrower.throwRuntimeException(1);
}
而检查异常信息的话就会解决这个问题,能确保是你想要的那个异常。单就这点来说,异常规则就要秒杀@Test注解里面的expected属性了。
不过如果你想验证的异常信息非常复杂呢?ExpectedException允许你传一个Hamcrest匹配器(matcher)给expectMessage方法(而不是一个字符串)。来看下这个例子:
@Test
public void verifiesMessageStartsWith() {
thrown.expect(RuntimeException.class);
thrown.expectMessage(startsWith("Illegal argument:"));
throw new RuntimeException("Illegal argument: i must be <= 0");
}
当然了,你还可以指定你自己的匹配器来进行消息验证。再看下这个例子。
@Test
public void verifiesMessageMatchesPattern() {
thrown.expect(RuntimeException.class);
thrown.expectMessage(new MatchesPattern("[Ii]llegal .*"));
throw new RuntimeException("Illegal argument: i must be <= 0");
}
class MatchesPattern extends TypeSafeMatcher<String> {
private String pattern;
public MatchesPattern(String pattern) {
this.pattern = pattern;
}
@Override
protected boolean matchesSafely(String item) {
return item.matches(pattern);
}
@Override
public void describeTo(Description description) {
description.appendText("matches pattern ")
.appendValue(pattern);
}
@Override
protected void describeMismatchSafely(String item, Description mismatchDescription) {
mismatchDescription.appendText("does not match");
}
}
校验异常对象
在有些场景下光匹配异常信息还不够。可能你的异常中有自定义的一些方法,你也想验证一下它们。完全没问题。给ExpectedException的expect方法指定一个matcher就搞定了。
@Test
public void verifiesCustomException() {
thrown.expect(RuntimeException.class);
thrown.expect(new ExceptionCodeMatches(1));
throw new CustomException(1);
}
class CustomException extends RuntimeException {
private final int code;
public CustomException(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
class ExceptionCodeMatches extends TypeSafeMatcher<CustomException> {
private int code;
public ExceptionCodeMatches(int code) {
this.code = code;
}
@Override
protected boolean matchesSafely(CustomException item) {
return item.getCode() == code;
}
@Override
public void describeTo(Description description) {
description.appendText("expects code ")
.appendValue(code);
}
@Override
protected void describeMismatchSafely(CustomException item, Description mismatchDescription) {
mismatchDescription.appendText("was ")
.appendValue(item.getCode());
}
}
注意了,这里同时实现了describeTo和describeMismatchSafely 两个方法。因为我希望如果测试失败的话输出的错误信息能看起来好一些 。看下它的输出:
java.lang.AssertionError:
Expected: (an instance of java.lang.RuntimeException and expects code <1>)
but: expects code <1> was <2>
检查异常原因
ExpectedException还有一个作用就是用来检查异常原因。这也可以通过自定义的匹配器来完成:
@Test
public void verifiesCauseTypeAndAMessage() {
thrown.expect(RuntimeException.class);
thrown.expectCause(new CauseMatcher(IllegalStateException.class, "Illegal state"));
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
private static class CauseMatcher extends TypeSafeMatcher<Throwable> {
private final Class<? extends Throwable> type;
private final String expectedMessage;
public CauseMatcher(Class<? extends Throwable> type, String expectedMessage) {
this.type = type;
this.expectedMessage = expectedMessage;
}
@Override
protected boolean matchesSafely(Throwable item) {
return item.getClass().isAssignableFrom(type)
&& item.getMessage().contains(expectedMessage);
}
@Override
public void describeTo(Description description) {
description.appendText("expects type ")
.appendValue(type)
.appendText(" and a message ")
.appendValue(expectedMessage);
}
}<2>
总结
ExpectedException规则是JUnit一个强大的特性。再加上Hamcrest匹配器,你的异常测试用例将变得更加健壮,并且可重复使用。
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
6. `ExpectedException`:预期异常测试,可以检查方法是否抛出了预期的异常。 六、异常处理 在测试中,有时我们需要验证方法是否正确抛出了预期的异常。可以使用`@Test(expected = Exception.class)`注解,指定预期...
异常测试也是JUnit4的一个重要特性,可以使用`assertThrows()`来断言预期的异常是否被抛出。例如,`assertThatThrownBy(() -> someCode()).isInstanceOf(ExpectedException.class)`。 JUnit4还引入了`Assume`类,...
9. 异常测试:JUnit允许测试代码是否抛出了预期的异常。通过使用@Test注解的expected属性或者使用@Rule注解的ExpectedException类来实现异常测试。 10. 测试规则(Rule):JUnit规则允许你在测试方法执行前后执行...
在实际项目中,我们可以按照以下步骤编写和运行JUnit4测试: 1. 引入JUnit4依赖:在项目构建文件中(如Maven或Gradle)添加JUnit4的依赖。 2. 创建测试类:创建一个类,并使用`@RunWith(JUnit4.class)`注解标记为...
在Eclipse中使用JUnit4进行单元测试是一种常见的开发实践,它可以帮助程序员确保代码的质量和可靠性。JUnit4是Java编程语言中最流行的单元测试框架之一,它提供了丰富的注解、断言和测试工具,使得测试过程更加简洁...
3. **异常测试**:通过`@Test(expected = Exception.class)`可以检查方法是否抛出了预期的异常。 4. **测试套件**:多个测试类可以通过`@RunWith(Suite.class)`和`@Suite.SuiteClasses`组合在一起,形成一个测试...
例如,JUnit自带的`ExpectedException` Rule可以帮助我们捕获和验证预期的异常: ```java import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; public class MyTest { @...
3. **异常测试**:你可以使用 `@Test(expected = Exception.class)` 来检查测试方法是否抛出了预期的异常类型。这使得异常处理的测试变得简单。 4. **测试套件(Test Suites)**:通过 `@Suite` 注解,可以组合多个...
3. **异常测试**: 使用 `@Test` 注解时,可以指定预期的异常类型,如 `@Test(expected = NullPointerException.class)`,当测试方法抛出预期的异常时,测试视为通过。 4. **参数化测试**: JUnit4 提供了 `@...
- 实践参数化测试和异常测试,了解如何创建自定义规则。 - 学习如何结合Mockito等库进行模拟对象测试。 通过深入研究JUnit4的源码,你可以理解其内部工作机制,提升测试技能,同时为可能的框架扩展或自定义打下...
JUnit 4.8.1 是一个广泛使用的Java编程语言的单元测试框架,它极大地简化了对Java代码进行测试的过程。这个版本是JUnit系列的一个特定发行版,提供了许多增强的功能和改进,以帮助开发者确保他们的代码质量。以下是...
还有`@Rule`可以定义自定义的测试规则,比如`ExpectedException`用于捕获预期的异常。 **版本对比** - **注解支持**:JUnit4引入了注解,使得测试代码更加简洁,而JUnit3需要使用特定的命名规则。 - **断言增强**...
接下来,我们将关注如何使用JUnit进行单元测试: 1. **测试类(Test Class)**:为你的DAO创建一个测试类,通常以`Test`作为后缀。在测试类中,你可以使用`@Before`和`@After`注解定义在每个测试方法之前和之后运行...
- **使用假设**:使用 `@Assume` 注解可以在测试之前检查一些假设条件,如果条件不满足,则测试将被跳过。 - **测试套件**:通过 `@RunWith(Suite.class)` 注解可以创建包含多个测试类的测试套件。 - **使用 `...
异常测试是JUnit的另一个重要特性。通过`@Test(expected = Exception.class)`,你可以指定一个测试方法应该抛出特定类型的异常。如果方法没有抛出预期的异常或者抛出了其他类型的异常,那么测试就会失败。 JUnit ...
JUnit是Java编程语言中最常用的单元测试框架之一,主要用于编写和执行可重复的自动化测试...通过使用junit-4.5.jar库,开发者可以利用上述功能进行高效的测试工作,而junit_license.txt则提供了关于库使用的法律指导。
- **库文件**:这是JUnit的主要运行时库,包含了所有JUnit框架需要的类和方法,开发者在项目中引用此jar文件即可使用JUnit进行测试。 - **依赖**:通常还需要`hamcrest-core.jar`,因为JUnit 4依赖了Hamcrest库...
JUnit还支持异常测试,可以通过`assertThrows()`方法来预期一个方法抛出特定的异常。另外,`ExpectedException`规则也可以用来验证预期的异常类型和消息。 在实际开发中,结合IDE如Eclipse或IntelliJ IDEA,可以很...