Based on my experience writing the Maven plugin, there are two levels of plugin testing: through unit test (using mocks) and through integration tests (using the maven-invoker plugin).
For integration tests, the maven archetype for the new maven plugins is already a good example out of the box, just do the following and look at it:
mvn archetype:generate \ -DgroupId=sample.plugin \ -DartifactId=hello-maven-plugin \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-plugin
By default, you will receive integration tests in the profile. An example maven project (under src \ it \ simple-it \ pom.xml) that can fulfill your plugin goals will also be available. I propose also to provide the result of the integration test with additional restrictions in this pom.xml. For example: you can add a Maven Enforcer Plugin rule to check for created files, if that makes sense for your plugin.
To more accurately answer the question of how to write unit tests for custom maven plugins, this is the approach I use:
- JUnit + Mockito.
- Work in test mode using @RunWith (MockitoJUnitRunner.class)
- Defined Mock Maven classes (MavenProject, Log, Build, DependencyNode, etc.) using @Mock annotations
- Initiate and link your mock objects in the @Before method (usually the setUp () method)
- Check your plugin :)
As an example, as a class variable of your unit test:
You may have the following mocked objects:
@Mock private MavenProject project; @Mock private Log log; @Mock Build build;
Then in your @Before method you need to add a large glue code as follows:
Mockito.when(this.project.getBuild()).thenReturn(this.build);
For example, I use Enforcer plugin to write some custom rules, so I need
@Mock private EnforcerRuleHelper helper;
And in the @Before method:
Mockito.when(this.helper.evaluate("${project}")).thenReturn(this.project); Mockito.when(this.helper.getLog()).thenReturn(this.log); Mockito.when(this.project.getBuild()).thenReturn(this.build); Mockito.when(this.helper.getComponent(DependencyGraphBuilder.class)).thenReturn(this.graphBuilder); Mockito.when(this.graphBuilder.buildDependencyGraph(this.project, null)).thenReturn(this.node);
Thus, these layouts will be easy to use in your tests. For example, you must have the first dummy test in order to test it for an empty assembly as follows (below when testing a custom Enforcer rule):
@Test public void testEmptyBuild() throws Exception { try { this.rule.execute(this.helper); } catch (EnforcerRuleException e) { Assert.fail("Rule should not fail"); } }
If you need to test the dependencies on your assembly, for example, you can write utility methods as follows:
private static DependencyNode generateNode(String groupId, String artifactId, String version) { DependencyNode node = Mockito.mock(DependencyNode.class); Artifact artifact = Mockito.mock(Artifact.class); Mockito.when(node.getArtifact()).thenReturn(artifact); // mock artifact Mockito.when(artifact.getGroupId()).thenReturn(groupId); Mockito.when(artifact.getArtifactId()).thenReturn(artifactId); Mockito.when(artifact.getVersion()).thenReturn(version); return node; }
To easily create dependencies in the dependency graph of your assembly, follow these steps:
List<DependencyNode> nodes = new ArrayList<DependencyNode>(); nodes.add(generateNode("junit", "junit", "4.12")); Mockito.when(node.getChildren()).thenReturn(nodes);
NOTE. You can improve the utility method if you need additional information (for example, a scope or a classifier for a dependency).
If you also need to make fun of the plugin configuration because you need to scan existing plugins and their configuration, for example, you can do this as follows:
List<Plugin> plugins = new ArrayList<Plugin>(); Plugin p = new Plugin(); // no need to mock it p.setArtifactId("maven-surefire-plugin"); Xpp3Dom conf = new Xpp3Dom("configuration"); Xpp3Dom skip = new Xpp3Dom("skip"); skip.setValue("true"); conf.addChild(skip); p.setConfiguration(conf); plugins.add(p); Mockito.when(this.build.getPlugins()).thenReturn(plugins);
Obviously, I will not consider all possible cases, but I am sure that you understand the approach and use. Hope this helps.