Junit等待并处理异常后断言

时间:2015-02-03 15:12:17

标签: java junit exception-handling mockito assert

在第一次和第二次通话时抛出的方法:

public void foo() throws Exception

试验:

@test
public void testFooThrowsAtFirstAndSecondTime(){
    boolean thrown;
    try {
       foo();
    } catch (Exception e) {
       thrown = true;
    }
    assertTrue(thrown);

    thrown = false;
    try {
       foo();
    } catch (Exception e) {
       thrown = true;
    }
    assertTrue(thrown);

    foo();
}

你能帮我找到更好的解决方案吗? 使用Mockito获得更好的解决方案也是可以接受的。

我的意思是,如果我可以在测试中避免尝试/捕获甚至多次尝试/捕获。在其他语言或jAssert中,我认为即使在春天也有如下声明:

assertThrows(method(..)) //PseudoCode

我认为与Mockito或JUnit 4.x有类似的事情。

我知道

@Test(expected=Exception)

但是,如果我期待一次投掷并且测试结束后,这只能被接受。

5 个答案:

答案 0 :(得分:5)

我不认为每个方法调用都是可行的。

我会像这样编写测试:

@Test
public void testFooThrowsAtFirstAndSecondTime() throws Exception {
  try {
    foo();
    fail("foo did not throw an exception");
  } catch (Exception ex) { }

  try{
    foo(); 
    fail("foo did not throw an exception");
  } catch (Exception ex) { }

  foo();
}

答案 1 :(得分:3)

如果你想在异常后恢复执行,那么这里的关键是the try block is crucial。您可以将其分解为方法或库,但必须在测试方法中调用它。

有效的方法:

  • 我更喜欢的you and nrainier cite fail()成功的try { foo(); fail("foo did not throw an exception"); } catch (Exception ex) { } 成语:

    List myList = new ArrayList();
    catchException(myList).get(1);  // myList is wrapped here
    assert caughtException() instanceof IndexOutOfBoundsException;
    
  • catch-exception是一个库,与Mockito一样,包装传递的对象并在每个方法周围放置一个try块。 Mockito关于最终方法和类的警告也适用于此,所以这并不总是有效。

    assertThrows(() -> methodThatThrows())

    请注意,catch-exception处于“维护模式”,因为Java 8解决方案(下面)更加可靠。

  • 任何解决方案,如assertThrows(new Runnable() { @Override public void run() { methodThatThrows(); } }); (Java 8)或:

    public void assertThrows(Runnable block) {
      try {
        block.run();
        fail("Block didn't throw.");
      } catch (Exception ex) { }
    }
    

    ...在Java 6/7中。重要的是, assertThrows在methodThatThrows 之前被调用,因此它可以调用methodThatThrows。感谢Stefan的pointing out Fishbowl,但你可以轻松自己写一个等价物:

    @Test(expected=YourException.class)

不起作用的事情:

  • try将上升到JUnit包装您的测试方法的ExpectedException块。之后,Control永远不会返回测试方法。

  • JUnit4的assertThrows(methodCallThatThrows()) @Rule看起来很诱人,但因为它包装了整个测试方法,所以你必须在调用抛出异常的方法之前设置期望值。

  • 任何看似methodCallThatThrows的内容。在assertThrows被调用之前,Java会尝试从try中获取返回值,因此>中的任何{{1}}块都无法帮助

答案 2 :(得分:1)

使用Java 8,您可以使用Fishbowl库。

@Test
public void testFooThrowsAtFirstAndSecondTime(){
  Throwable firstException = exceptionThrownBy(() -> foo());
  assertEquals(Exception.class, firstException.getClass());

  Throwable secondException = exceptionThrownBy(() -> foo());
  assertEquals(Exception.class, secondException.getClass());

  foo()
}

也可以将此库与Java 6和7一起使用。但是你必须使用匿名类。

@Test
public void testFooThrowsAtFirstAndSecondTime(){
  Throwable firstException = exceptionThrownBy(new Statement() {
    public void evaluate() throws Throwable {
      foo();
    }
  });
  assertEquals(Exception.class, firstException.getClass());

  Throwable secondException = exceptionThrownBy(new Statement() {
    public void evaluate() throws Throwable {
      foo();
    }
  });
  assertEquals(Exception.class, secondException.getClass());

  foo()
}

答案 3 :(得分:1)

如果你不幸的是必须为8之前的某个版本的java编写代码,那么你不能每个例外使用一行代码。

但是如果你使用的是java 8,那么就可以像Stefan Birkner所说的那样做。

现在,如果您不想仅为一个方法包含整个库,那么这里有一个适合您的方法,复制from my blog

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause();
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

所以,你的测试代码就像这样:

@Test
public void testFooThrowsAtFirstAndSecondTime()
{
    expectException( Exception.class, this::foo );
    expectException( Exception.class, this::foo );
    foo();
}

答案 4 :(得分:-1)

@Test(expected=Exception.class)