Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run each JUnit Test with a Separate ClassLoader (no, really)

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.

like image 799
EngineerBetter_DJ Avatar asked Feb 17 '15 21:02

EngineerBetter_DJ


People also ask

How do you run a test method in a specific order in junit4?

For JUnit 4, putting this annotation on the test class solved the problem. @FixMethodOrder(MethodSorters. JVM): Leaves the test methods in the order returned by the JVM. This order may vary from run to run.

Can we run parallel tests in JUnit?

Once parallel test execution property is enabled, the JUnit Jupiter engine will execute tests in parallel according to the provided configuration with declared synchronization mechanisms.

What is BeforeClass and AfterClass in JUnit?

org.junitIf you allocate expensive external resources in a BeforeClass method you need to release them after all the tests in the class have run. Annotating a public static void method with @AfterClass causes that method to be run after all the tests in the class have been run.


Video Answer


2 Answers

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.

like image 170
EngineerBetter_DJ Avatar answered Oct 18 '22 03:10

EngineerBetter_DJ


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

like image 27
eckes Avatar answered Oct 18 '22 03:10

eckes