Search code examples
javamavenmaven-surefire-pluginjava-module

Maven compile and provided scopes for unit testing of JPMS module with surefire-plugin


Trying to test my maven project (one parent pom and several modules (jpms modules)) I got annoying Error occurred in starting fork:

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M4:test (default-test) on project com.foo.plugin: There are test failures.
...
Error occurred in starting fork, check output in log
Process Exit Code: 1
org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
...
Error occurred in starting fork, check output in log
Process Exit Code: 1
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:690)
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:285)
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:248)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1217)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:1063)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:889)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginM

A solution I found, for example, here suggested to set <forkCount>0</forkCount> in surefire-plugin configuration. However, such solution doesn't allow to run tests on module-path, so I went to this surefire issue.

Surefire developers (thanks to them) found out that the reason was in maven scope of the dependencies I used. In my project I have:

         <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <version>2.1.6</version>
            <scope>provided</scope> <!-- NOTE IT -->
        </dependency>
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope> <!-- NOTE IT -->
        </dependency>

And they said it had to be:

          <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <version>2.1.6</version>
            <scope>compile</scope> <!-- NOTE IT -->
        </dependency>
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>2.3.2</version>
            <scope>compile</scope> <!-- NOTE IT -->
        </dependency>

And when I changed the scope my project was tested by surefire without problems. Both dependencies jakarta.ws.rs-api and jakarta.xml.bind-api are JPMS modules and are required by my JPMS modules.

So the question, is the problem in my code (provided is wrong if I want to run my tests for my JPMS module) or the problem is in surefire plugin?


Solution

  • NOTE: You can freely remove <scope>compile</scope> since no declaration of the scope in your POM means that the Maven will use the default value compile anyway.

    The scope of provided is the project architecture aspect.

    It is used in situations when the application server contains WS API (even if different arfifact file name). This way we mark it provided which makes the WAR file smaller and the WS API artifact would not be included.

    In situations where you are also building serverless application and you are building your own container, then no scope of provided is needed to declare. There the artifact will appear within the Fat JAR which is what you expect.

    So as you can see the dependency marked as provided copes with classpaths. It appears on Compiler classpath but it does not appear in runtime.

    There is one more feature in the scope provided. It is the inheritance, where such of dependency cannot be inherited transitively. If you have such dependency witht the scope provided in a POM, then the inheritance would not see the dependency in a dependent child POM.

    For more information pls see Maven documentation.

    http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

    This scope is only available on the compilation and test classpath, and is not transitive.