Example example_test
Part of the full Java 9 Jigsaw modules example suite.
|
Authors
Originally written by Martin Lehmann, Kristine Schaal and RĂ¼diger Grammes (cf. original repository). Migrated for Java Modules support documentation of Apache MavenTM in the course of the Maven Support & Care program by Gerd Aschemann (and other team members) as forked repository. Please add discussions, requirements, bugfixes, etc. to the fork instead of the original. |
What is this example about?
Modules in this example
-
modfib (contains the code to be tested), modtest.blackbox, modtest.whitebox
-
No Main class, JUnit is started instead in the run scripts.
-
There are separate scripts to compile and run the whitebox and blackbox tests.
Module Dependency Graph, created with DepVis
Example shows …
Example for Testing
-
Blackbox testing
-
Whitebox testing
For blackboxtesting, the test classes can be managed in a separate module. Only the public interface of modfib has to be accessed in a blackbox test.
In a whitebox test, the internal classes of modfib are subject to tests and therefore must be accessible by test classes. In this example, we use the patch feature. Test classes are patched into modfib when compiling the test classes and when starting the tests. Advantages:
-
modfib does not have to export internal classes to a test module (neither statically in the module-info nor during compile or runtime via --add-exports).
-
test code can be separated from operational code and is therefore not deployed to any operational environment.
Output
This example uses golden master testing to ensure output consistency.
The expected output is compared with actual output using verify.sh.
Expected Output
JUnit version 4.12
.Running blackbox test class pkgblacktest.BlackBoxTest.doBlackboxTest(): Testing modfib's exported class pkgfib.Fibonacci
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
Actual Output
JUnit version 4.12
.Running blackbox test class pkgblacktest.BlackBoxTest.doBlackboxTest(): Testing modfib's exported class pkgfib.Fibonacci
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
Maven 4 Output
JUnit version 4.12
.Running blackbox test class pkgblacktest.BlackBoxTest.doBlackboxTest(): Testing modfib's exported class pkgfib.Fibonacci
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
JUnit version 4.12
.Running whitebox test class pkgfib.WhiteBoxTest.doWhiteboxTest(): Testing modfib's internal class pkgfib.internal.MathHelper
OK (1 test)
Maven 4 Migration
This example has been migrated to Maven 4 with whitebox testing handled entirely by Maven’s Module Source Hierarchy, and only blackbox testing requiring a hybrid shell script approach.
Migration Challenges
The example demonstrates two distinct testing patterns:
-
Whitebox testing: Test code needs access to modfib’s internal (non-exported) packages using
--patch-module -
Blackbox testing: Separate test module (modtest.blackbox) with its own module-info.java that requires modfib
Maven 4’s Module Source Hierarchy automatically handles whitebox testing when test sources are declared with scope="test" for the same module. The blackbox test module, however, cannot be easily integrated into the same Maven build.
Migration Strategy
Whitebox Testing: Pure Maven 4
Maven 4 automatically handles whitebox testing through its Module Source Hierarchy:
<sources>
<source>
<module>modfib</module>
<directory>src/modfib/main/java</directory>
</source>
<source>
<module>modfib</module>
<directory>src/modfib/test/java</directory>
<scope>test</scope>
</source>
</sources>
When Maven 4 detects test sources for the same module (indicated by scope="test"), it automatically:
-
Compiles main sources to
target/classes/modfib/ -
Compiles test sources with
--patch-module modfib=…totarget/test-classes/modfib/ -
Generates appropriate module patch arguments in
target/test-classes/META-INF/maven/module-info-patch.args
No explicit module-info-patch.maven configuration file is needed - Maven’s Module Source Hierarchy implementation handles this automatically!
Blackbox Testing: Hybrid Approach with javac
The blackbox test module (modtest.blackbox) is a separate module that cannot be compiled by the same Maven invocation. It is compiled separately using javac:
javac -d mods \
--module-path amlib:mlib \
--module-source-path "src/*/test/java" \
$(find src/modtest.blackbox/test/java/ -name "*.java")
This allows modtest.blackbox to:
-
Be a proper module with its own module-info.java declaring
requires modfib; requires junit; -
Access JUnit as an automatic module from amlib/
-
Depend on modfib.jar compiled by Maven
Technical Implementation
Directory Structure
The m4/ directory uses symbolic links to maintain a single source of truth:
m4/src/modfib/main/java -> ../../../../src/modfib
m4/src/modfib/test/java/pkgfib -> ../../../../../src/modtest.whitebox/pkgfib
m4/src/modtest.blackbox/test/java -> ../../../../src/modtest.blackbox
Compilation Scripts
-
compile-whiteboxtest.sh: Runs Maven 4test-compile(automatic --patch-module), packages modfib.jar and whitebox test JAR -
compile-blackboxtest.sh: Compiles modtest.blackbox with javac, packages blackbox test JAR -
compile.sh: Orchestrates both compilation phases
Execution
Three test scenarios are executed:
-
Blackbox test: Tests modfib’s exported API using modtest.blackbox module
-
Whitebox test: Tests modfib internals using
--patch-module modfib=patchlib/modfib.jar -
Whitebox test with options file: Same as (2) but loads options from
@run-whiteboxtest_optionsfile
The run scripts produce identical output to the original implementation, verified by golden master testing.
Maven 4 Benefits
Maven 4’s Module Source Hierarchy provides significant value:
-
Automatic --patch-module handling: No manual configuration needed for whitebox testing - Maven detects the need for patching when test sources are declared with
scope="test"for the same module -
Dependency management: Automatic download of JUnit and Hamcrest to amlib/
-
Java 11 bytecode: Maven runs with JDK 17 but compiles for Java 11 via
maven.compiler.release -
Clean separation: Whitebox tests integrated into Maven build, blackbox tests compiled separately via shell script
Only the blackbox test module requires a hybrid approach with javac, demonstrating a practical pattern for integrating Maven 4 with custom test module compilation.