Java 8 让这变得容易多了,而 Kotlin/Scala 更是如此。
我们可以写一个小工具类
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
然后你的代码就变得简单了:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
如果您无法访问 Java-8,我会使用令人痛苦的旧 Java 工具:任意代码块和简单的注释
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
最后,我最近爱上了 kotlin:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
虽然有很多空间可以摆弄你想要如何表达这一点,但我一直是fluent assertions 的粉丝。
关于
您以错误的方式处理此问题。只需测试您的功能:如果抛出异常,测试将自动失败。如果没有抛出异常,您的测试将全部变为绿色。
这在原则上是正确的,但在结论上是错误的。
Java 允许控制流出现异常。这是由 JRE 运行时本身在 API 中完成的,例如 Double.parseDouble 通过 NumberFormatException 和 Paths.get 通过 InvalidPathException。
假设您已经编写了一个组件来验证 Double.ParseDouble 的数字字符串,可能使用正则表达式,可能是手写解析器,或者可能嵌入了一些其他域规则,这些规则将 double 的范围限制为特定的东西,如何最好地测试这个组件?我认为一个明显的测试是断言,当解析结果字符串时,不会引发异常。我会使用上面的assertDoesNotThrow 或/*comment*/{code} 块编写该测试。类似的东西
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
我还鼓励您在 input 上使用 Theories 或 Parameterized 参数化此测试,以便您可以更轻松地将此测试用于其他输入。或者,如果你想变得异国情调,你可以选择test-generation tool(和this)。 TestNG 对参数化测试有更好的支持。
我觉得特别令人不快的是使用@Test(expectedException=IllegalArgumentException.class) 的建议,这个例外非常广泛。如果您的代码发生更改,使得被测组件的构造函数具有if(constructorArgument <= 0) throw IllegalArgumentException(),并且您的测试为该参数提供了 0,因为它很方便——这很常见,因为生成测试数据是一个非常困难的问题——,那么您的测试将是绿条,即使它没有测试任何内容。这样的测试比没用还糟糕。