Equivalent to @DirtiesContext(...) for Surefire + JUnit?

Viewed 213

I'm using the maven-surefire-plugin with junit 4.1.4. I have a unit test which relies on a 3rd party class that internally uses static { ... } code block to initiate some variables. For one test, I need to change one of these variables, but only for certain tests. I'd like this block to be re-executed between tests, since it picks up a value the first time it runs.

When testing, it seems like surefire instantiates the test class once, so the static { ... } code block is never processed again.

This means my unit tests that change values required for testing are ignored, the static class has already been instantiated.

Note: The static class uses System.loadLibrary(...), from what I've found, it can't be rewritten to be instantiated, static is the (rare, but) proper usage.

I found a similar solution for Spring Framework which uses @DirtiesContext(...) annotation, allowing the programmer to mark classes or methods as "Dirty" so that a new class (or in many cases, the JVM) is initialized between tests.

How do you do the same thing as @DirtiesContext(...), but with maven-surefire-plugin?

public class MyTests {
    @Test
    public void test1() {
        assertThat(MyClass.THE_VALUE, is("something-default"));
    }

    @Test
    public void test2() {
        System.setProperty("foo.bar", "something-else");
        assertThat(MyClass.THE_VALUE, is("something-else"));
        //                            ^-- this assert fails
        //                                value still "something-default"
    }
}
public class MyClass {
    static {
        String value;
        if(System.getProperty("foo.bar") != null) {
            value = System.getProperty("foo.bar"); // set to "something-else"
        } else {
            value = "something-default";
        }
    }
    public static String THE_VALUE = value;

}
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>4.1.2</version>
      </plugin>
1 Answers

static initialization blocks in java are something that can't be easily handled by JUnit. In general static stuff doesn't play nicely with unit testing concepts.

So, assuming you can't touch this code, your options are:

Option 1:

Spawn a new JVM for each test - well, this will work, but might be an overkill because it will aggravate the performance

If you'll follow this path, you might need to configure surefire plugin with:

forkCount=1
reuseForks=false

According to the surefire plugin documentation this combination will execute each test class in its own JVM process.

Option 2:

Create a class with a different class loader for every test.

Basically in Java if class com.foo.A is created by ClassLoader M is totally different than the same class com.foo.A created by ClassLoaded N. This is somewhat hacky but should work.

The overhead is much smaller than in option 1. However you'll have to understand how to "incorporate" new class loaders into the testing infrastructure.

For more information about the creation of the custom class loader read for example this tutorial

Related