18

How can I have JUnit use a separate ClassLoader for each test class it executes?

I am writing a JUnit TestRunner for a library that sets a lot of static variables. I essentially want to reset all of these between each test class, without needing to know what all of them are. I do not want to be coupled to intimate knowledge of the framework, as whenever the library changes internally then my TestRunner will break.

Before I go any further, I want to make absolutely clear that I really do want to do this.

  • I do not have control over the library.
  • I do not have the option of not using static variables.
  • I do not want to use reflection or Powermock, as I don't want to know what's going on in the library.
  • I do not want to use Maven config to fork testing processes, as then the testing utility is tied to a build tool.

Every other answer I can find on StackOverflow just says "don't do that," which isn't helpful. First person to answer with "static variables are dumb" wins a doughnut.

DeejUK
  • 12,891
  • 19
  • 89
  • 169

2 Answers2

13

In the end I wrote my own, loosely based on another Stack Overflow answer (which didn't work for me).

It's now on GitHub, and Maven Central. https://github.com/BinaryTweed/quarantining-test-runner

<dependency>
    <groupId>com.binarytweed</groupId>
    <artifactId>quarantining-test-runner</artifactId>
    <version>0.0.1</version>
</dependency>

To use it annotate your test classes accordingly:

@RunWith(QuarantiningRunner.class)
@Quarantine({"com.binarytweed"})
public class MyIsolatedTest {
...

The linked answer didn't work for me as the test class itself needs to be loaded in a separate ClassLoader, as then all the classes it references will use the same loader. Quarantining is inclusive (rather than exclusive) as you need the JUnit @Test annotations to be loaded by the parent ClassLoader, otherwise JUnit can't find any testable methods as it uses Class<Test> as a key in a lookup map.

Community
  • 1
  • 1
DeejUK
  • 12,891
  • 19
  • 89
  • 169
2

MyFaces has a TestPerClassLoaderRunner which is (despite its name) what you are looking for.

eckes
  • 10,103
  • 1
  • 59
  • 71
  • Thanks. I've tried that, and it fails to find `java.lang.Object`! I think maybe I need to pass through the 'current' classpath to it... – DeejUK Feb 17 '15 at 22:22
  • Did you start it from Maven? Looks like it is very specific to its class path structure. – eckes Feb 17 '15 at 22:26
  • Nah, Eclipse. Will give that a go, and if it works then see if I can make it generic enough to work from either. – DeejUK Feb 18 '15 at 11:31