Maven Plugin Testing - In a Modern way - Part V

In the previous part of the series - Maven Plugin Testing - In a Modern way - Part IV we have seen how to define goals to run Maven. In this part we will take a deeper look how we can define system properties for a Maven call to be used.

Let us take a look at a simple example taken from the previous part.

1@MavenJupiterExtension
2class BaseIT {
3
4  @MavenTest
5  @MavenGoal("verify")
6  void the_first_test_case(MavenExecutionResult result) {
7     ...
8  }
9}

This will run Maven with the goal verify. So what could you do to prevent running the unit tests or even any tests at all within that integration test case? What would you usually do on plain command line? You would have added -DskipTests to your Maven command line. How could you do the above integration test example? Very easy like this:

 1@MavenJupiterExtension
 2class PropertyIT {
 3
 4  @MavenTest
 5  @MavenGoal("verify")
 6  @SystemProperty("skipTests")
 7  void goal_clean_skiptests (MavenExecutionResult result) {
 8     ...
 9  }
10}

That means in the end that Maven will be called like the following:

1mvn -DskipTests verify

Let us go a step further and see how to write a test case for a plugin which should be called like this:

1mvn ...:failure -DexecutionException=true -Dexception="This is the value of exception."

The above could be expressed like this:

 1@MavenJupiterExtension
 2class PropertyIT {
 3
 4  @MavenTest
 5  @MavenGoal("clean")
 6  @MavenGoal("${project.groupId}:${project.artifactId}:${project.version}:failure")
 7  @SystemProperty(value = "executionException", content = "true")
 8  @SystemProperty(value = "exception", content = "This is the value of exception.")
 9  void goal_failure_execution(MavenExecutionResult result) {
10     ...
11  }
12}

You can see two things here. First you can repeat the @SystemProperty to define multiple system properties and second you can make a clear separation between the name and property value.

As you might already expected you can create a meta annotation where you can combine the properties used in the previous example into this single meta annotation:

1@Target({ElementType.METHOD, ElementType.TYPE})
2@Retention(RUNTIME)
3@Inherited
4@SystemProperty(value = "executionException", content = "true")
5@SystemProperty(value = "exception", content = "This is the value of exception.")
6public @interface ExecutionException {
7}

If reconsider this it's thought a bit too short, because that can be made better like this:

 1@Target({ElementType.METHOD, ElementType.TYPE})
 2@Retention(RUNTIME)
 3@Inherited
 4@MavenTest
 5@MavenGoal("clean")
 6@MavenGoal("${project.groupId}:${project.artifactId}:${project.version}:failure")
 7@SystemProperty(value = "executionException", content = "true")
 8@SystemProperty(value = "exception", content = "This is the value of exception.")
 9public @interface FailureGoalWithExecutionException {
10}

So the defined meta annotation can now being used to make the test looking like this:

1@MavenJupiterExtension
2class PropertyIT {
3
4  @FailureGoalWithExecutionException
5  void goal_failure_execution(MavenExecutionResult result) {
6     ...
7  }
8}

You can define the previous described meta annotation in the example project and see how it feels to use it.

Based on convenience you can of course create a meta annotation like this:

1@Target({ElementType.METHOD, ElementType.TYPE})
2@Retention(RUNTIME)
3@Inherited
4@SystemProperty("skipTests")
5public @interface MavenSkipTests {
6}

or other things. If you have good ideas do not hesitate to file in a feature request for the project so it could be made permanent part of it.

So this it is for Part V. If you like to learn more about the Integration Testing Framework you can consult the users guide. If you like to know the state of the release you can take a look into the release notes.

If you have ideas, suggestions or found bugs please file in an issue on github.

An example project which shows the previous example can be found on GitHub.