How do you organize tests in a modular Java project?
Asked Answered
D

2

17

I am creating a modular build (using module-info.java) on GitHub, but when adding a module-info.java to the modules that I want modular, no tests can be executed...

How can I achieve this?

I am using the following versions:

  • junit.jupiter version 5.3.0 (first take was also unsuccessful with version 5.2.0)
  • maven-compiler-plugin version 3.8.0 (first take was also unsuccessful with version 3.7.0)
  • maven-surefire-plugin version 2.22.0 (first take was also unsuccessful with version 2.21.0)

A typical error from the failing tests looks like:

java.lang.reflect.InaccessibleObjectException: Unable to make com.github.jactor.rises.commons.dto.UserDtoTest() accessible: module jactor.rises.commons does not "opens com.github.jactor.rises.commons.dto" to unnamed module @65e98b1c

Dicephalous answered 31/8, 2018 at 6:54 Comment(0)
G
19

Welcome to Testing In The Modular World!

Which kind of tests do you want write?

Extra-module tests: Create a test-only project (no "src/main" directory) and declare a "src/test/java/module-info.java" module descriptor.

In-module tests: As it was from Day 1 you need to "blend in"/merge/shadow your test classes into your main classes or vice versa. Here you have mainly two ways to achieve this:

  • "compile modular main sources" and "patch plain test sources" at test-runtime with some additional "JVM options hacking the Module system" to execute tests.
  • "compile modular test sources" and "patch modular main sources" at compile-time to execute tests.

Blog

https://sormuras.github.io/blog/2018-09-11-testing-in-the-modular-world

Examples

Background and other resources

Gail answered 31/8, 2018 at 7:20 Comment(12)
This is super uber level of description. I am pretty sure those examples would have a good CTR in the coming days. Thanks for making an answer collaborating those examples.Headroom
this is a bit "high level" coding and requires hard focus to achieve. i am trying to gain experience in the modular world of java, but this is hard to achieve, when there are no particular useful examples and little useful documentation of this... can you provide some "step-by-step" instructions? i need to fully remove my surefire-plugin?Dicephalous
from what I am reading, it seems to me that the maven lifecycle needs to be adjusted, first a test compile (which compiles test classes and main classes into the same module) and test it, then if it is successful, it builds the module without test classes. black box/white box? too many considerations? I want to test all classes in my module (not only the exported ones)...Dicephalous
@Dicephalous Have a look at this blueprint: github.com/sormuras/sandbox/tree/master/… -- it is still work-in-progress but outlines the idea(s) in a minimal running example.Gail
@Gail I just want to run unit tests with JUnit and Maven for an extremely simple modularized library, one module exporting one package, zero dependencies besides JUnit and AssertJ (test scope). Works fine with JUnit Jupiter 5.1.1, JUnit Platform 1.1.1, and Maven Surefire 2.19.1. But same errors as @Dicephalous with JUnit Jupiter 5.3.0 and Maven Surefire 2.22.0. Surefire option --illegal-access=permit doesn't help. Do I really need your de.sormuras junit-platform-maven-plugin?Reenareenforce
Does it work with the junit-platform-maven-plugin?Gail
Yes, although IntelliJ is very confused by the src/test/java/module-info.java I added to follow your blueprint (complains that 'module-info.java' already exists in the module). Surely this isn't how people are expected to use JUnit. I don't see anything in the JUnit user guide about how to test modularized projects. Is 5.3.0 just not ready for that use case? Is 5.1.0 doing some ugly hack to make it work that has been removed?Reenareenforce
The version if JUnit doesn't matter. It's all about organzing your tests in the modular world: sormuras.github.io/blog/2018-09-11-testing-in-the-modular-worldGail
Eclipse is just as confused. I'm sorry but standard tooling just doesn't support this approach.Nanosecond
I'm with @Reenareenforce here. but it seems this is far, far easier with gradle?Opportuna
If we need to specify a provides clause for tests (service loading in tests) ... can that be patched and if so how? I haven't found a way ... which points me more toward maven-surefire-plugin useModulePath false.Elidiaelie
Does a correct META-INF/services not kick in? docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.htmlGail
C
2

There is a (new) option in the Maven Surefire plugin called useModulePath. This option enables to use the traditional Java 8 class path instead of the module path and ignores a module-info.class from the main classes not turning on the Java module mode, i.e. all class on the calls path can be used.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <!--  allow to use unnamed modules -->
        <useModulePath>false</useModulePath>
    </configuration>
</plugin>

That way the test sources can be kept as there were in Java 8. Only The main classes have to be modularized.

Chung answered 24/12, 2021 at 0:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.