Today, I started to write unit tests for a Maven plug-in I am working on.
For the moment, I created 3 mojos and registered them for a custom packaging I defined in the plexus file called components.xml.
Before implementing these mojos, I wanted to set up unit tests.
For this, I followed these explanations on Maven’s web site about the maven-plugin-testing-harness plug-in. The thing is that it just did not work.
So, hopefully, I hope this post will help those in troubles.
First, you must add in your POM dependencies that are marked as provided in the maven-plugin-testing-harness plug-in.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <prerequisites> <maven>3.0.3</maven> </prerequisites> <parent> <groupId>net.roboconf</groupId> <artifactId>parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>net.roboconf</groupId> <artifactId>roboconf-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <name>Roboconf :: Maven Plug-in</name> <packaging>maven-plugin</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.version>3.2.2</maven.version> </properties> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>${maven.version}</version> </dependency> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>net.roboconf</groupId> <artifactId>roboconf-core</artifactId> <version>${project.version}</version> </dependency> <!-- THIS is the important part --> <dependency> <groupId>org.apache.maven.plugin-testing</groupId> <artifactId>maven-plugin-testing-harness</artifactId> <version>3.2.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-aether-provider</artifactId> <version>${maven.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-core</artifactId> <version>${maven.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-compat</artifactId> <version>${maven.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-model</artifactId> <version>${maven.version}</version> <scope>test</scope> </dependency> <!-- END of the important part --> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.3</version> <configuration> <goalPrefix>roboconf</goalPrefix> </configuration> </plugin> </plugins> </build> </project>
I am using Maven 3.2.2. And in my test, I use JUnit 4.
So, the code to make it work is a little bit different than the one on Maven’s wiki. In particular, the getTestFile method does not exist anymore with the version 3.x of the maven-teting plug-ins.
So, here is a little snippet.
package net.roboconf.maven; import java.io.File; import junit.framework.Assert; import org.apache.maven.plugin.testing.MojoRule; import org.apache.maven.plugin.testing.resources.TestResources; import org.junit.Rule; import org.junit.Test; /** * @author Vincent Zurczak - Linagora */ public class ValidateMojoTest { @Rule public MojoRule rule = new MojoRule(); @Rule public TestResources resources = new TestResources(); @Test public void testInvalidProject() throws Exception { File projectCopy = this.resources.getBasedir( "project--invalid" ); File pom = new File( projectCopy, "pom.xml" ); Assert.assertNotNull( pom ); Assert.assertTrue( pom.exists()); ValidateMojo mojo = (ValidateMojo) this.rule.lookupMojo( "validate", pom ); Assert.assertNotNull( mojo ); mojo.execute(); } }
And my file structure is the following one.
+ src/main/java
++ …
+ src/test/projects
++ project–invalid
+++ pom.xml
++ project–valid
+++ pom.xml
+++ …
All the Maven projects I use for tests are declared under src/test/projects.
I use a TestResources rule to copy this projet in my target directory and work on a copy. And I use a MojoRule rule to retrieve information and execute actions on my project through my plug-in.
For the record, the validate mojo I invoke in my unit test was associated with my Maven plug-in in the src/main/resources/META-INF/plexus/components.xml file. This is because I use a custom packaging for my project.
Eventually, here is the POM I have under the project–invalid directory.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <prerequisites> <maven>3.0.3</maven> </prerequisites> <groupId>net.roboconf.test</groupId> <artifactId>this-is-for-test-only</artifactId> <version>1.0-SNAPSHOT</version> <name>This is for Test ONLY</name> <packaging>roboconf-app</packaging> <build> <plugins> <plugin> <groupId>net.roboconf</groupId> <artifactId>roboconf-maven-plugin</artifactId> <version>${project.version}</version> <extensions>true</extensions> <configuration></configuration> </plugin> </plugins> </build> </project>
Roboconf-maven-plugin is the plug-in under test.
That’s it. The original sources are (or will be soon) on GitHub.
Many thanks, your post helps a lot. I have the same problem to find out the missing and undocumented dependencies. Takes a long time to find your post, but my configuration suits from now on your example and all my tests are now running with no fault 🙂
My plugin uses a parameter whose default value is ${project}. This is null under test. Should lookupMojo also populate this?
Nope, you have to populate it by hand.
See as an example https://github.com/roboconf/roboconf-platform/blob/master/miscellaneous/roboconf-maven-plugin/src/test/java/net/roboconf/maven/PackageTargetMojoTest.java
Testing a Maven plug-in is far from being convenient… 😦
Ah, I found out how to do it. You use lookupConfiguredMojo(): this.mojo = (FoobarMojo)this.mojoRule.lookupConfiguredMojo(mavenProject, “foobar”);
Now its ${project} is populated.