views:

210

answers:

6

I am using JUnit to write some higher level tests for legacy code that does not have unit tests.

Much of this code "swallows" a variety of unchecked exceptions like NullPointerExceptions (e.g., by just printing stack trace and returning null). Therefore the unit test can pass even through there is a cascade of disasters at various points in the lower level code.

Is there any way to have a test fail on the first unchecked exception even if they are swallowed?

The only alternative I can think of is to write a custom JUnit wrapper that redirects System.err and then analyzes the output for exceptions.

+3  A: 

If you execute the tests in your IDE's debugger you can configure the IDE to break when an exception is thrown.

Nathan Hughes
+4  A: 

In lack of a concrete solution, my answer's pretty general:

Such code smells (e.g. swalling exceptions) are best cleaned up step by step (class by class) when you encounter them while bugfixing the legacy system. Code quality tools (e.g. Findbugs, PMD, Checkstyle or even Sonar Quality Server) help you find those things.

A way to "catch" swallowed exceptions automatically is to use AspectJ compiler. You can declare aspects to generate a compile-time error in your IDE when certain code conventions are violated. Alternatively, you can weave at runtime the classes under test and let AspectJ rethrow such exceptions, so they can be recorded by the JUnit runner.

mhaller
+1 - PMD already has a rule to look for empty catch blocks. It probably wouldn't be hard to extend this to make rules to look for other common ways to fail at exception handling.
Bill the Lizard
A: 

It could be possible to mock the Exceptions you want to catch with a mocking framework that modifies the bytecode, or with an AOP framework. I imagine you could modify the constructor to throw a more fatal Exception, or to set some flag in your test code.

Chris Lercher
+1  A: 

I believe Exception is just a standard class in the SDK libraries.

If you extracted it, modified it and put it somewhere on your classpath before the SDK, I think it should replace the one in the SDK (If not you could put your "new" exception back into the SDK jar)

Anyway, your new exception could set a static value that can be read by the testing framework.

May not be the most elegant solution but it doesn't require any "Magic"

Bill K
That isn't so easy, as the code is in a java. package, and the JDK has some security mechanisms to prevent that kind of tinkering that you have to work around.
Yishai
Bill K
@Bill K, yes the boot classpath is the basic idea, but that would mean a separately made and compiled class wrapped in a separate jar, or some other fancy fiddling to separate those implementations, and then you can't have that class interact with any other classes (like a JUnit class) and your test has to call it, not the other way around. It is doable, it is just so easy.
Yishai
This could help http://java.sun.com/j2se/1.5.0/docs/guide/standards/
Ondra Žižka
+1  A: 

I would try to use AOP to throw failures. Something like this should work (note, I haven't tested this, and you obviouslly need to have AspectJ Setup to use AOP annotations)

public class ClassUnderTest
{
   private static Boolean exceptionThrown;


   @Before
   public void resetExceptionFlag()
   {
      ClassUnderTest.exceptionThrown = false;
   }

   @Test
   public void myTestMethod()
   {

      //....
      // My Test Exception Code
      //....

      assertFalse(ClassUnderTest.exceptionThrown);
   }

   @Aspect
   static class TestAspects
   {
      @Pointcut("handler(Exception)")
      public void intereceptAllExceptions(){}

      //This is Fully Qualified because of the conflict with the junit Before annotation above
      @org.aspectj.lang.annotation.Before("intereceptAllExceptions()")
      public void flagExceptionThrown()
      {
         ClassUnderTest.exceptionThrown = true;

  }

} }

Daniel Roop
A: 

Perhaps you can paste the code that you are trying to test. Mostly likely you would have to use some of "remapper" testing frameworks such as powermock or jmockit to manipulate the classloader manipulation in JVM. But a sample of class under test would help determine the approach required.

Kartik