For anyone following along who wants to get get whitebox testing
working, here is the changes I made:

https://github.com/JodaOrg/joda-money/pull/143/files#diff-9c5fb3d1b7e3b0f54bc5c4182965c4fe1f9023d449017cece3005d3f90e8e4d8R126

These changes cause Maven to test Joda-Money three times:
- once with main and test on the classpath
- once with main on the modulepath and tests on the classpath
- once with main and tests on the modulepath

This uses an extra module-info.java file for testing. This is managed
in such a way that IDEs are not messed up.

The code is tested with Java 21 and Maven 3.8.8/3.9.9.

Stephen


On Mon, 23 Sept 2024 at 16:47, Stephen Colebourne <scolebou...@joda.org> wrote:
>
> 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