我知道有一种方法是:

@Test
public void foo() {
   try {
      // execute code that you expect not to throw Exceptions.
   } catch(Exception e) {
      fail("Should not have thrown any exception");
   }
}

还有更干净的方法吗?(可能使用了Junit的@Rule?)


当前回答

虽然这篇文章已经发布6年了,但是Junit世界已经发生了很多变化。现在可以使用Junit5

org.junit.jupiter.api.Assertions.assertDoesNotThrow()

Ex:

public void thisMethodDoesNotThrowException(){
   System.out.println("Hello There");
}

@Test
public void test_thisMethodDoesNotThrowException(){
  org.junit.jupiter.api.Assertions.assertDoesNotThrow(
      ()-> thisMethodDoesNotThrowException()
    );
}

希望它能帮助那些正在使用Junit5新版本的人

其他回答

我偶然发现这一点是因为SonarQube的规则“squid:S2699”:“向这个测试用例添加至少一个断言。”

我有一个简单的测试,它的唯一目标是不抛出异常。

考虑这段简单的代码:

public class Printer {

    public static void printLine(final String line) {
        System.out.println(line);
    }
}

可以添加什么样的断言来测试这个方法? 当然,您可以尝试捕获它,但这只是代码膨胀。

解决方案来自JUnit本身。

如果没有抛出异常,并且你想显式地说明这种行为,只需添加预期,如下例所示:

@Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
    Printer.printLine("line");
}

Test.None.class是预期值的默认值。

如果您导入org.junit.Test。没有,你可以这样写:

@Test(expected = None.class)

你可能会觉得更有可读性。

以下是所有检查或未检查的异常都无法通过测试:

@Test
public void testMyCode() {

    try {
        runMyTestCode();
    } catch (Throwable t) {
        throw new Error("fail!");
    }
}

我遇到了同样的情况,我需要检查异常是否在应该抛出的时候抛出,并且仅在应该抛出的时候抛出。 最终使用异常处理程序对我的好处如下代码:

    try {
        functionThatMightThrowException()
    }catch (Exception e){
        Assert.fail("should not throw exception");
    }
    RestOfAssertions();

对我来说,主要的好处是它非常直截了当,并且在相同的结构中检查“如果且仅当”的另一种方式非常容易

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()
}

尽管有很多空间可以随意改变你想要如何表达这一点,但我一直喜欢流畅的断言。


关于

你想错了。只需测试您的功能:如果抛出异常,测试将自动失败。如果没有抛出异常,您的测试将全部显示为绿色。

这在原则上是正确的,但在结论上是不正确的。

Java允许控制流的异常。这是由JRE运行时本身在Double等api中完成的。parseDouble通过NumberFormatException和路径。通过invalidpatheexception获取。

Given you've written a component that validates Number strings for Double.ParseDouble, maybe using a Regex, maybe a hand-written parser, or perhaps something that embeds some other domain rules that restricts the range of a double to something specific, how best to test this component? I think an obvious test would be to assert that, when the resulting string is parsed, no exception is thrown. I would write that test using either the above assertDoesNotThrow or /*comment*/{code} block. Something like

@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));
}

我还鼓励您使用Theories或Parameterized对输入参数化这个测试,这样您就可以更容易地对其他输入重复使用这个测试。或者,如果您想要与众不同,您可以使用测试生成工具(以及这个工具)。TestNG对参数化测试有更好的支持。

What I find particularly disagreeable is the recommendation of using @Test(expectedException=IllegalArgumentException.class), this exception is dangerously broad. If your code changes such that the component under test's constructor has if(constructorArgument <= 0) throw IllegalArgumentException(), and your test was supplying 0 for that argument because it was convenient --and this is very common, because good generating test data is a surprisingly hard problem--, then your test will be green-bar even though it tests nothing. Such a test is worse than useless.

在这个问题上遇到了麻烦,因为我创建了一些泛型方法

@Test
void testSomething() {
   checkGeneric(anComplexObect)
}

在https://newbedev.com/sonarqube-issue-add-at-least-one-assertion-to-this-test-case-for-unit-test-with-assertions中提出了一些注释的东西。

解决方案要简单得多。将“checkGeneric”方法重命名为“assertGeneric”就足够了。

@Test
void testSomething() {
  assertGeneric(anComplexObect)
}