views:

544

answers:

5

I've been bit a few times by Java assert statements that didn't fail in the JUnit test suite because assertions weren't enabled in JUnit's JVM instance. To be clear, these are "black box" assertions inside implementations (checking invariants, etc) not the assertions defined by the JUnit tests themselves. Of course, I'd like to catch any such assertion failures in the test suite.

The obvious solution is to be really careful to use -enableassertions whenever I run JUnit, but I'd prefer a more robust solution. One alternative is to add the following test to every test class:

  @Test(expected=AssertionError.class)
  public void testAssertionsEnabled() {
    assert(false);
  }

Is there a more automatic way to accomplish this? A system-wide configuration option to JUnit? A dynamic call I could put in the setUp() method?

A: 

I propose three possible (simple?) fixes which work for me after a quick test (but you might need to check the side effects of using a static-initializer-block)

1.) Add a static-initializer block to those testcases which rely on assertions being enabled

import ....
public class TestXX....
...
    static {
        ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
    }
   ...
   @Test(expected=AssertionError.class)
   ...
...

2.) Create a base-class which all of your test-classes extend which need assertions enabled

public class AssertionBaseTest {
    static {
        //static block gets inherited too
        ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
    }
}

3.) Create a test suite which runs all your test

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({
    //list of comma-separated classes
    /*Foo.class,
    Bar.class*/
})
public class AssertionTestSuite {
    static {
        //should run before the test classes are loaded
        ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
    }
    public static void main(String args[]) {
        org.junit.runner.JUnitCore.main("AssertionTestSuite");
    }
}
jitter
+1 Very cool hidden Java gem.
Alexander Pogrebnyak
That doesn't work in my case. It relies on the order that the classes get loaded.
Chris Conway
Sorry, but this will not work as expected. Assertions must be enabled when loading and initializing a class and setting the default assertion status on the class loader will only affect classes, which are loaded later.
jarnbjo
You are of course both correct. Will rethink this problem
jitter
+1  A: 

As a friend of mine says... why take the time to write an assert if you are just going to turn it off?

Given that logic all assert statements should become:

if(!(....))
{
    // or some other appropriate RuntimeException subclass
    throw new IllegalArgumentException("........."); 
}

To answer your question a way you probably want :-)

import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;


@RunWith(Suite.class)
@Suite.SuiteClasses({
        FooTest.class,
        BarTest.class
        })
public class TestSuite
{
    @BeforeClass
    public static void oneTimeSetUp()
    {
        ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
    }
}

Then run the test suite rather than each test. This should (works in my testing, but I did not read the internals of the JUnit framework code) result in the assertion status being set before any of the test classes are loaded.

TofuBeer
There's a bit of confusion in your answer between assertions and other types of runtime checks such as preconditions. An assertion is a statement which, basically, cannot possibly fail. To check one in to your codebase should be roughly the equivalent of betting $50 of your own money that that stack trace would never appear in production even if asserts were turned on.Asserts can be useful while you're in the process of editing and testing a class, but then they become basically comments after that.Compilable comments.
Kevin Bourrillion
Unless the assertion was shown to slow the code down to the point where it was a problem I would rather have them on all the time. Preconditions/post conditions and any other type of assert statement - if you took the time to write it why turn it off?
TofuBeer
+2  A: 

Alternatively, you may compile your code such that assertions cannot be turned off. Under Java 6, you may use "fa.jar – Force assertion check even when not enabled", a small hack of mine.

Adrian
Cool idea! It's not going to work for me, though, if it doesn't work in Eclipse.
Chris Conway
A: 

Windows->Preferences->JUnit has an option to add -ea everytime a new launch configuration is created. It adds the -ea option to the Debug Configuration as well.

The full text next to a check box is "Add '-ea' to VM arguments when creating a new JUnit launch configuration"

RAbraham
A: 

I also posted a question on here as to how to enable assertions, and I would still like to be able to turn them on without coding them.

But your little assertion class you extend is wonderful, I googled a while until I found it, so thanks a bunch for your post!