Write Unit Tests for a Maven plug-in

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.

4 thoughts on “Write Unit Tests for a Maven plug-in

  1. 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 🙂

      1. Ah, I found out how to do it. You use lookupConfiguredMojo(): this.mojo = (FoobarMojo)this.mojoRule.lookupConfiguredMojo(mavenProject, “foobar”);

        Now its ${project} is populated.

Leave a reply to Daniel Witt Cancel reply