JUnit 4 and Suspend-on-Exception

2019-04-06 08:19发布

问题:

When an uncaught exception is thrown in my code, I am used to having the debugger stop at the throwing statement so that I can examine the local variables and the members of all objects involved at the moment that the exception was thrown. With IntelliJ Idea this can be accomplished by going to Run, View Breakpoints, selecting the Exception Breakpoints tab, checking Any exception, and making sure that the Caught exception checkbox is unchecked, while the Uncaught exception checkbox is checked. With Eclipse and with Visual Studio (for C#) it is something different, but along the same lines.

The ability to have the debugger behave this way is extremely useful; so useful in fact, that I structure the main loop of my programs accordingly: on the release version, the main loop is of course embedded inside a try-catch-all; but on the debug version, there is no try-catch block in the main loop, so that any exceptions that are not caught anywhere within my program will remain uncaught, so that the debugger will suspend my program at the moment that they are thrown.

When testing my Java classes with JUnit, however, I have a problem: the debugger does not stop on any exception. Instead, what happens is that not only expected, but also unexpected exceptions get automagically caught, and I am given a post-mortem exception stack trace to try and make sense out of. That's not very cool.

I used to think that this is happening because JUnit makes use of java.lang.reflect.Method.invoke(), which catches all exceptions and transforms them to TargetInvocationExceptions, but then I wrote my own custom JUnit runner, which knows my test class personally and directly invokes its methods without Method.invoke(), and the problem persists. This means that the problem lies high up within core JUnit.

So, does anyone else have the same problem? Does anyone know of a solution so that we can have the debugger suspend program execution on unexpected exceptions while testing with JUnit?

Related (unanswered) question: Suspend on uncaught runtime exceptions in Eclipse Junit test runner

Related (unanswered) question: How to break into debugger within a jUnit test case?

Related (partly answered) question: Break on Exception in Eclipse using jUnit (The accepted answer says that "if you debug a single method in jUnit, the breakpoints start to work. If an entire class or package is debugged in jUnit, the debugger doesn't work.")

回答1:

I hope I understand the question correctly, so correct me if I'm wrong, but:

  • you have a test, which throws an exception, which you do not catch yourself (so it, in that sense, is uncaught)
  • when you debug this test with the JUnit4 testrunner, JUnit shows you that the test fails (it threw the exception)
  • but the thread is not suspended, which is what you want to achieve
  • even though you have preferences | java | debug | suspend execution on uncaught exceptions enabled

In that case, I believe this is the intended behavior, JUnit catches and swallows your exception, so it is not uncaught as far as eclipse is concerned, as described here https://bugs.eclipse.org/bugs/show_bug.cgi?id=414133

You can have eclipse suspend any way by setting up your own rules for suspending on caught exceptions. Debug perspective | breakpoint view | J! icon | check suspend on caught exception



回答2:

As a workaround for use when investigating a test failure, you could create an instance of the offending test class in main method and call its test method by hand with your exception breakpoints method (which is very cool by the way, thanks for the question). That way, the method isn't being called reflectively.