Separate ClassLoader per test #4203
-
I try to migrate some JUnit4 tests to JUnit5 and struggle with a problem: the project uses arquillian to deploy war files to a webserver and runs tests in the server side. Thus, the war file is created with Shrinkwrap and arquillian deploys it to the container. Some tests in this project simulate the arquillian approach without actually using arquillian: they create a war file in one classloader, then they do some tests in a separate classloader to test for example that all necessary classes are contained in the package. Currently, they do this with a How could I handle this with JUnit5? I found the "LauncherInterceptor" (https://junit.org/junit5/docs/snapshot/user-guide/#launcher-api-launcher-interceptors-custom, added by #3091), but this one seems to be created only once per test suite run. So I would have to create a separate project for each of thoses tests with one LauncherInterceptor that invokes the method that creates the archive? Or is there a better approach? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 5 replies
-
I created a sample based on a It installs a custom classloader for the entire session that then checks if a custom class loader is needed for each test class: For the detection I used a custom When you run
This should work for all class-based test engines, not just Jupiter. But there's a Jupiter-specific issue for providing an extension API (#3028). Feel free to chime in! |
Beta Was this translation helpful? Give feedback.
-
I've done something similar to what @marcphilipp suggests. I create a FacadeClassLoader and set it as the thread context classloader, and it delegates to the 'real' classloader for each test. It mostly works well. |
Beta Was this translation helpful? Give feedback.
-
Cool, many thanks! Will give it a try tomorrow. |
Beta Was this translation helpful? Give feedback.
-
Whow, this is rather tricky... Still trying to understand the code and adapt it to the existing tests... @marcphilipp Attached is a reworked version of your sample. I converted it to maven and switched the URLClassLoader to a ShrinkWrapClassLoader. Several questions:
But after adding the "filteringClassLoader" to my real word sample, the content of my test method breaks with a error "...is in unnamed module of loader 'app'" => will have to do further research. |
Beta Was this translation helpful? Give feedback.
-
I thought I am done with my current implementation - the tests using the But another test fails with a @marcphilipp Do you have any idea about this and do you have a suggestion how to avoid it? The exception is:
A simple suggestion could be to extract all tests using the |
Beta Was this translation helpful? Give feedback.
-
@marcphilipp Thanks for your help and the suggested sample. So I mark this discussion as "closed". I will continue working on migrating my test suite. Unfortunately, arquillian is also not fully ready for JUnit5, so other prerequisites are missing. Hopefully, one day #3028 will be implemented and an easier apporach for a SeparateClassLoader can be used. |
Beta Was this translation helpful? Give feedback.
I created a sample based on a
ServiceLoader
-registeredLauncherSessionListener
here: https://github.com/marcphilipp/gradle-sandbox/tree/master/classloader-per-test-classIt installs a custom classloader for the entire session that then checks if a custom class loader is needed for each test class:
https://github.com/marcphilipp/gradle-sandbox/blob/baaa1972e939f5817f54a3d287611cef0601a58d/classloader-per-test-class/src/test/java/org/example/ClassLoaderReplacingLauncherSessionListener.java#L23-L44
For the detection I used a custom
@SeparateClassLoader
annotation that specifies a factory for creating the class loader. In the sample, aURLClassLoader
is created that (to mimick your use case) …