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