Hi All!

In the JDK 9 module environment running unit tests is more complex task than it 
was in the classpath mode.
The problems of test compilation and execution are nicely described in the 
following thread 
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2016-March/thread.html#6587 
on the jigsaw-dev mailing list. Also there is lots of different test scenarios 
as described in
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2016-March/007152.html.

Basically there are two problems:
The first problem is that modules enforce module boundaries, only exported 
packages are seen
from other modules.
The second problem is the module readability - dependency among modules.


 The tests can be executed in the following ways:

1st) In classpath mode - the current way JunitTask executes tests
All the libraries, project artifacts, junit and test classes are on classpath. 
In this scenario the classpath artifacts become a part of the unnamed module. 
There is no problem with module boundaries or readability as all artifacts are 
a part of a single module (unnamed module). However the tests do not run in the 
same environment as the product which executes the project in its own module. 
Also services registered in the module-infos are not available in the 
ServiceLoader. This is probably not acceptable.

2nd) Blackbox testing.
The tests have its own module, in other words there is a module-info in the 
test sources in addition to module-info in sources. All the libraries, project 
artifact, test classes and junit are on modulepath. The test’s module-info 
requires the project module (sources) and junit end exports all test packages 
to make them accessible by junit. The limitation is that in such a setup only 
classes exported by the project module can be tested (unless 
-XaddExports:sourceModule/sourcePackage=testModule is passed to the JVM). The 
-addmods:testModule JVM option is needed to make testModule active and readable 
by junit. Next limitation is that the test classes cannot be in the same 
packages as tested sources because split packages are not supported by the 
module system.
The module readability graph: 
http://wiki.netbeans.org/wiki/images/a/a9/Blackbox_module_path.png

The complete java command line is:
java -mp build/test/classes:build/classes/:lib/lib.jar:lib/junit.jar  
-addmods:testModule  -m junit/org.junit.runner.JUnitCore app.AppTest

3rd) Whitebox testing - probably most common
The tests are inlined into the source module.
All the libraries, project artifact, test classes and junit are on modulepath 
(there is an option to keep junit on classpath which I will
explain later). As the test classes are in the same module as project sources 
there is no problem with module boundaries and readability among project 
sources and tests. The test packages need to be exported to be accessible by 
junit by -XaddExports:sourceModule/testPackage=junit and made readable by JUnit 
-XaddReads:sourceModule=junit -addmods sourceModule.
The module readability graph: 
http://wiki.netbeans.org/wiki/images/c/ca/Whitebox_module_path.png

The complete java command line is:
java -mp build/classes/:lib/lib.jar:lib/junit.jar 
-Xpatch:sourceModule=build/test/classes -addmods sourceModule 
-XaddExports:sourceModule/testPackage=junit -XaddReads:sourceModule=junit -m 
junit/org.junit.runner.JUnitCore app.AppTest


There is also a possibility to keep the junit.jar on the classpath rather than 
on the modulepath. In this case junit becomes a part of an unnamed module, when 
on modulepath it becomes an automatic module. The same JVM options are 
required, only the -XaddReads:sourceModule=junit changes to 
-XaddReads:sourceModule=ALL-UNNAMED. The disadvantage of this solution is that 
unit test can read the unnamed module which contains junit but may contain 
other unwanted jar files on classpath. The only advantage of these solution is 
that it does not need module execution (-m JVM option).
The module readability graph: 
http://wiki.netbeans.org/wiki/images/3/38/Whitebox_class_path.png

The complete java command line is:
java -mp build/classes/:lib/lib.jar -cp lib/junit.jar 
-Xpatch:sourceModule=build/test/classes -addmods sourceModule 
-XaddExports:sourceModule/testPackage=junit -XaddReads:sourceModule=ALL-UNNAMED 
org.junit.runner.JUnitCore app.AppTest



The JUnit task needs to be extended to support all three scenarios.
There are two possibilities how to extend the JUnitTask:

1st) Minimal needed changes
Just add a modulepath to JUnit task. When junit library is not found on the 
classpath but found on the module path do the modular execution by -m 
junit/<mainclz> rather than classpath execution. The user is responsible for 
passing the -XPatch, -XaddExports, -XaddReads, -addmods JVM options. Options 
like -XaddExports are harder to calculate as they require list of test 
packages. But it can be done by the following pathconvert:

<dirset id="packages" dir="build/test/classes" includes="*"/>
<pathconvert refid="packages" property=“exports.cmd” pathsep=" ">
   <chainedmapper>
       <flattenmapper/>
       <globmapper from="*" to="-XaddExports:${module.name}/*=junit"/>
   </chainedmapper>
</pathconvert>


2nd) Extend Junit task to automatically set the -XPatch, -XaddExports, 
-XaddReads, -addmods options for modular execution.
This will require adding more attributes to JUnit task (path to test classes to 
do the -XPatch, ability to disable the automatic options).

As the 2nd solution is a superset of the 1st one I will start with it.
Any thoughts and comments are welcome
Thanks,
— Tomas
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@ant.apache.org
For additional commands, e-mail: dev-h...@ant.apache.org

Reply via email to