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

Naman
  • 27,789
  • 26
  • 218
  • 353
jactor-rises
  • 2,395
  • 2
  • 22
  • 44

2 Answers2

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

Sormuras
  • 8,491
  • 1
  • 38
  • 64
  • 2
    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. – Naman Aug 31 '18 at 09:32
  • 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? – jactor-rises Aug 31 '18 at 14:59
  • 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)... – jactor-rises Aug 31 '18 at 15:14
  • @jactor-rises Have a look at this blueprint: https://github.com/sormuras/sandbox/tree/master/sors-modular-testing-blueprint -- it is still work-in-progress but outlines the idea(s) in a minimal running example. – Sormuras Sep 01 '18 at 12:26
  • 1
    @Sormuras 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 @jactor-rises 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`? – gdejohn Sep 04 '18 at 20:21
  • Does it work with the `junit-platform-maven-plugin`? – Sormuras Sep 04 '18 at 22:16
  • 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? – gdejohn Sep 04 '18 at 23:42
  • The version if JUnit doesn't matter. It's all about organzing your tests in the modular world: https://sormuras.github.io/blog/2018-09-11-testing-in-the-modular-world – Sormuras Sep 12 '18 at 07:33
  • 1
    Eclipse is just as confused. I'm sorry but standard tooling just doesn't support this approach. – billmill Sep 21 '18 at 12:11
  • I'm with @gdejohn here. but it seems this is far, far easier [with gradle?](https://stackoverflow.com/questions/46613214/java-9-maven-junit-does-test-code-need-module-info-java-of-its-own-and-wher/63386799#63386799) – Eugene Aug 13 '20 at 01:40
  • 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. – Rob Bygrave Mar 17 '22 at 03:33
  • Does a correct META-INF/services not kick in? https://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html – Sormuras Mar 17 '22 at 10:09
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.

k_o_
  • 5,143
  • 1
  • 34
  • 43