Uploaded image for project: 'Maven Surefire'
  1. Maven Surefire
  2. SUREFIRE-2190

optional dependencies and JPMS modules confuse surefire

    XMLWordPrintableJSON

Details

    Description

      The surefire plugin, when executing tests for JPMS code, patches the test code "into" the module under test (using --patch-module). This work for compile+runtime dependencies (`requires`) but not for compile required/runtime optional dependencies (requires static).

      The plugin only adds the module under test using --add-modules module.under.test.id to the JVM that is executing the test classes. As requires static dependencies are not loaded transitively, any dependency that is optional for the main artifact but required for test code is not found.

      clone and build the test repo: https://github.com/hgschmie/msurefire2190

      This repo contains three artifacts with identical code:

      thing1 builds a main artifact without JPMS
      thing2 builds a main artifact with a strong (requires) dependency on jakarta.annotation.
      thing3 builds a main artifact with a compile-only (requires static) dependency on jakarta.annotation.
      The code and its test classes are otherwise identical.

      Running mvn -DskipTests clean install builds all three modules and the test code.

      Running mvn surefire:test passes the tests in the first two modules but fails in the third.

      Explanation:

      The surefire plugin, when it executes tests using JPMS adds all referenced modules to the module path (in this case the module under test itself and the jakarta.annotations-api jar). It then adds the main module using --add-modules and patches this module with the test classes (using -patch-module, so that the test classes execute as part of the module.

      In case of a compile+runtime (requires) relationship, the JVM will find the required JPMS module on the module path and add it as accessible. This is why the "thing2" tests pass.

      In case of a compile only/runtime optional (requires static) relationship, the JVM will not add the module transitively as it is considered a compilation-only dependency. For the code under test to be able to access the classes from jakarta.annotation, they must be declared as a module. However, the test code only adds the module under test with --add-modules. So the test classes do not find any classes from the jakarta.annotation module and the test fails.

      The fix is simple: Instead of just adding the module under test using --add-modules, the surefire plugin should use -add-modules ALL-MODULE-PATH.

      Which is correct, because the code is not looking for compile time only dependencies but actual runtime dependencies where the code under execution may also need to access optional runtime dependencies (see
      https://nipafx.dev/java-modules-optional-dependencies/ for a slightly longer explanation).

      Attachments

        Issue Links

          Activity

            People

              henning Henning Schmiedehausen
              henning Henning Schmiedehausen
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: