Hi all,
Apologies for the long email, but whitebox testing is a complex topic.
I know not everyone agrees with whitebox testing, but it is a major
factor in how many projects are written, and IMO Maven should fully
and easily support it.

A "whitebox mode" test has two module-info.java files, both with the
same module name. The goal is to support unit testing with full access
to the internals of the module as in the "good ole days" while
ensuring that the test occurs on the module-path (test failures can
occur on the module-path which do not occur on the class-path, and
vice versa):

root
- pom.xml
- src/main/java
-- module-info.java
-- mypackage
--- Main,java
- src/main/resources
-- mypackage
--- main.txt
- src/test/java
-- module-info.java
-- mypackage
--- Test,java

The main module-info would be something like:
  module mymodule {
    exports mypackage;
  }

The test module-info would be something like:
  open module mymodule {
    // duplicate contents of main module-info
    exports mypackage;
    // any additional test dependencies/services
    requires transitive org.junit.jupiter;
  }

The good news is that a setup like this mostly works today in Maven
(tested with v3.9.9 and Java 21).
However there are three key issues:

The way Maven currently operates is:

1) In `testCompile`, the test source code is compiled using:
  --module-path target/test-classes:target/classes
  --patch-module mymodule=src/main/java

2) In `surefire`, the tests are run with:
--module-path target/test-classes:target/classes:<< dependencies >>
--class-path << surefire jar files >>

What actually happens is (I think) very surprising. TestCompile
compiles BOTH the main and test source code into
`target/test-classes`:
target/classes contains
- module-info.class (from src/main/java)
- mypackage/Main.class
- mypackage/main.txt
target/test-classes contains
- module-info.class (from src/test/java)
- mypackage/Main.class
- mypackage/Test.class

This results in three issues:

A) The code in `src/main/java` is compiled twice, which is
unnecessary, surprising and slows things down

B) There is no need to refer to `target/classes` on the module-path,
as it is not used in TestCompile or Surefire.

C) Any resource files (src/main/resources) are UNAVAILABLE to
Surefire, which results in the tests failing, eg.
`Main.class.getResourceAsStream("main.txt")` will return null. This is
because Surefire sees the code in target/test-classes as the complete
definition of the module, and as shown above `main.txt` is not present
in `target/test-classes`.

-----
Option 1:
Do nothing. End users can fix the resource file issue by adding this
to the pom.xml:
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
    <argLine>--patch-module mymodule=src/main/resources;</argLine>
   </configuration>
  </plugin>

This causes Surefire to pickup the resource folder and patch it into the module.

Option 2:
Automate the patch-module described above. When Surefire runs in
"whitebox mode", the --patch-module outlined above should be
automatically generated and added to the command line. Care will be
needed not to clash with any patch-module the user adds manually.

This fixes issue C.

Option 3:
Properly address the issue. maven-compiler-plugin already recognises
that there are two module-info.java files and checks the names. If
they are different it sets up "blackbox mode". IMO,
maven-compiler-plugin needs an official "whitebox mode".
The correct approach, as far as I can determine, is for TestCompile to
do the following:
  --module-path target/test-classes
  --patch-module mymodule=target/classes
This avoids the main source code being compiled twice - it is patched
in instead.

The same change needs to be applied to Surefire
  --module-path target/test-classes:<< dependencies >>
  --patch-module mymodule=target/classes

This fixes issues A , B and C. (The resource files in target/classes
are patched in alongside the .class files).
Note that the java command line generates a warning about duplicate
module-info.class files, but that is expected in this case,and can be
ignored.

---
So, what do people think? Is there appetite to raise an issue to get
option 2 or 3 done?

thanks for reading this far
Stephen Colebourne

PS. IDEs don't like the two module-info.java files of whitebox
testing, but that's OK - Maven isn't beholden to IDEs. It also turns
out there is an easy workaround for IDEs (which I can describe in
another email, as this one is too long)
PPS. I know about the suggested module-info.test file - lets not get
into that discussion here

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@maven.apache.org
For additional commands, e-mail: users-h...@maven.apache.org

Reply via email to