如何模拟Maven插件环境和项目配置

7

我想为我的maven插件编写单元测试(junit4)。我找到的所有示例都使用“AbstractMojoTestCase”(junit3:-()。为了摆脱这个问题,我在这里找到了答案。但问题是如何实例化Mojos:

MyMojo myMojo = (MyMojo) lookupMojo( "touch", pom );

这意味着每个测试用例都需要一个pom文件作为输入数据。但是有没有一种方法可以模拟(我会使用Mockito)项目模型呢?lookupMojo(String groupId, String artifactId, String version, String goal, PlexusConfiguration pluginConfiguration)可能是一个很好的起点吗?在这种情况下,我想模拟“PlexusConfiguration”,但是需要哪些方法呢?一些maven-plugin testing doku使用类似于“MavenProjectStub”的类。但我无法得到一个关于如何创建mojo以及它在创建时讲话哪些接口的一致的图像。
如果我只能找到一个完美的解决方案...
@inject
MyMojo testObject;

并且只需模拟所需的所有内容即可使其工作(主要是我需要@Parameters)


有关此事的任何消息吗?这将非常有用。 - pigiuz
没有新闻,但是投票支持这个问题可能会有帮助! :-) - dermoritz
1个回答

6
基于我编写Maven插件的经验,有两个级别可以对插件进行测试:通过单元测试(使用mock)和通过集成测试(使用maven-invoker-plugin)。
对于集成测试,Maven新插件的maven原型已经提供了一个很好的示例,只需执行以下命令并查看即可:
 mvn archetype:generate \
  -DgroupId=sample.plugin \
  -DartifactId=hello-maven-plugin \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DarchetypeArtifactId=maven-archetype-plugin

默认情况下,您将获得一个包含集成测试的配置文件来开始。还将提供一个示例Maven项目(位于src\it\simple-it\pom.xml下),可以执行您的插件目标。我建议在pom.xml中通过附加约束来强制执行您的集成测试结果。例如:如果对您的插件有意义,可以添加Maven Enforcer Plugin规则以检查创建的文件。
更具体地回答关于如何为自定义Maven插件编写单元测试的问题,以下是我使用的方法:
  • JUnit + Mockito。
  • 使用@RunWith(MockitoJUnitRunner.class)运行测试用例
  • 使用@Mock注释模拟Maven特定类(MavenProject、Log、Build、DependencyNode等)
  • 在@Before方法中初始化和链接您的模拟对象(通常是setUp()方法)
  • 测试您的插件 :)
例如,您可能拥有以下模拟对象作为单元测试的类变量:
@Mock
private MavenProject project;
@Mock
private Log log;
@Mock
Build build;

然后,在你的@Before方法中,你需要添加以下的一些粘合代码:
Mockito.when(this.project.getBuild()).thenReturn(this.build);

例如,我曾经编写一些自定义的Enforcer插件规则,因此我需要...
@Mock
private EnforcerRuleHelper helper;

在@Before方法中:

    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);

因此,将这些模拟对象用于测试将变得非常容易。例如,一个必备的首个虚拟测试是对空构建进行测试,如下所示(下面是针对自定义执行程序规则的测试):

@Test
public void testEmptyBuild() throws Exception {
    try {
        this.rule.execute(this.helper);
    } catch (EnforcerRuleException e) {
        Assert.fail("Rule should not fail");
    }
}

如果您需要测试构建的依赖关系,您可能需要编写以下实用方法:
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;
}

为了能够轻松地在构建的依赖图中创建依赖关系,可以按照以下方式操作:
List<DependencyNode> nodes = new ArrayList<DependencyNode>();
nodes.add(generateNode("junit", "junit", "4.12"));

Mockito.when(node.getChildren()).thenReturn(nodes);

注意:如果你需要进一步了解一个依赖项的作用域或分类器等详细信息,可以改进该实用方法。

如果你还需要模拟插件的配置,因为你需要扫描现有插件及其配置,例如,可以按照以下方式进行:

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);

我显然不会涵盖所有可能的情况,但我相信你已经了解了方法和用法。希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接