Index: src/main/groovy/util/GroovyTestCase.java =================================================================== --- src/main/groovy/util/GroovyTestCase.java (revision 19514) +++ src/main/groovy/util/GroovyTestCase.java Tue Mar 09 20:24:08 EST 2010 @@ -262,23 +262,41 @@ protected String shouldFailWithCause(Class clazz, Closure code) { Throwable th = null; + Throwable orig = null; try { code.call(); } catch (Throwable e) { th = e; - while(th.getCause()!=null) { + orig = e; + while (th != null && !th.getClass().getName().equals(clazz.getName())) { th = th.getCause(); } } - if (th==null) { + if (orig == null) { fail("Closure " + code + " should have failed with an exception caused by type " + clazz.getName()); - } else if (! clazz.isInstance(th)) { - fail("Closure " + code + " should have failed with an exception caused by type " + clazz.getName() + ", instead got Exception " + th); + } else if (th == null) { + fail("Closure " + code + " should have failed with an exception caused by type " + clazz.getName() + ", instead found these Exceptions:\n" + buildExceptionList(orig)); } return th.getMessage(); } + private String buildExceptionList(Throwable th) { + StringBuilder sb = new StringBuilder(); + int level = 0; + while (th != null) { + if (level > 1) { + for (int i = 0; i < level - 1; i++) sb.append(" "); + } + if (level > 0) sb.append("-> "); + sb.append(th.getClass().getName()); + sb.append("\n"); + th = th.getCause(); + level++; + } + return sb.toString(); + } + /** * Returns a copy of a string in which all EOLs are \n. */