Maven Plugin(Mojo)开发中单元测试备忘

昨天准备就现在开发中的问题写一个Maven插件,完成一些代码的自动生成。在好几年前写过几个插件,这次重新找开看后,发现原来的都很简单,所以都没有在开发期间的进行测试。考虑到这次写的稍微复杂一些,如果每次修改到东西都要到目标项目中进行测试,那么效率太差了,所以准备先把插件开发中相关的单元测试搞定。

谁成想,这样一下子发现了一个大坑。过程是这样的:

  • 首先在Maven的官网上查找相关的文档,发现原来codehaus这个组织已经关闭了,原来他们开发的很多插件都转移到各处。
  • 官司网上的文档对测试这块讲解很不清楚,如果按官网上的说明([How To Use Maven Plugin Testing Harness?]),过程中出现了几个问题:
    • 首先在测试时会报MavenExecuteResult、MavenSession、MavenResporitory等各种对象不存在的问题
    • 官网的例子使用的是比较老的继承AbstractMojoTestCase的方法,当解决了依赖的问题后,会发现如果在Mojo中使用类似${project.build.directory}等expression时,无法进行值的引用。
    • 这期间还发生了,在Mojo中使用@Parameter时在会出现

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.3:descriptor (default-descriptor) on project scaffold-maven-plugin: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.3:descriptor failed: String index out of range: -1 -> [Help 1]

幸好有google在(真难以相像如果使用百度会是一个怎么样的结果),经过长时间各种搜索发现了一篇最有用的文章Write Unit Tests for a Maven plug-in[感谢作者帮我解决了这个大问题],它解决了基本所有的问题,下面摘录一些要点:

  • 上面问题中的第一个,也就是各种对象不存在的问题,主要原因是在测试中需要使用若干个关联的jar包,但是在搜索中一个包一个包的添加,在运行中会出现版本不匹配的问题,各种纠结。应当按如下的方式配置想着的依赖:
    <?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>
    

在这个实例中使用的版本是3.2.2,我自己经过测试,发现3.2.3也是可以使用的。另外,由于在Mojo中会使用如MavenProject这样的对象,这样的类差不多都在maven-core中,如果在compile时发现类找不到,可以将依赖中下面几个scopetest的修改为provided

  • 在测试时,最早使用的是junit 3.8.1,所以使用的基类是AbstractMojoTestCase,这个类有很多问题,诸如在前面列举的。所以,最好使用junit4以后的版本,按文章中的写法,如下:
    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;
    
    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();
        }
    }
    

由于 走过了一些弯路,所以上面的代码是今天早上起床时才突然想到的,因为原来一起使用AbstractMojoTestCase,按那个思路在解决问题。今天早上突然回想起这个文章的这后半部分,说实在的,在刚看到文章时,this.rule.lookupMojo()这行其实出现了问题,所以就又回到原来的老路上。但是结合昨天查询到的其它的文章:

只要把测试用例中的代码修改为:
File projectCopy = this.resources.getBasedir("project-to-test");
File pom = new File(projectCopy, "pom.xml");
Assert.assertNotNull(pom);
Assert.assertTrue(pom.exists());

  MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
  ProjectBuildingRequest configuration = executionRequest.getProjectBuildingRequest()
              .setRepositorySession(new DefaultRepositorySystemSession());
  MavenProject project = rule.lookup(ProjectBuilder.class).build(pom, configuration).getProject();

  HibernateMojo mojo = (HibernateMojo) rule.lookupConfiguredMojo(project, "validate");
  Assert.assertNotNull(mojo);
  mojo.execute();

就可以解决在Mojo中无法识别${}expression的问题了。

  • 最后,项目的结构应当诸如:
    + src/main/java
    ++ …
    + src/test/projects
    ++ project–to-test
    +++ pom.xml
    ++ project–other-test
    +++ pom.xml
    +++ …
    其中,测试的pom.xml文件如下:
    <?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>
    

最后,以下是几个Mojo开发中有用的链接,备忘:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 我jdk版本是1.7.0_95,在网上查了一下1.7属于java7maven3.3+版本都支持java7,所以我使...
    liangxifeng833阅读 1,236评论 0 2
  • Maven编译代码的相关命令 第一、main目录下的主代码编写完毕后,使用Maven进行编译,在项目根目录下运行命...
    加油小杜阅读 1,112评论 0 2
  • 使用指导 如何添加外部依赖jar包 在Maven工程中添加依赖jar包,很简单,只要在POM文件中引入对应的<de...
    静默虚空阅读 2,723评论 0 13
  • 写作要求 坚持写作第9天~主题写作 阅读应该是与写作并行的,阅读是写作的基础,所以,大家要完成的任务是读一本自己曾...
    Albert陈凯阅读 311评论 0 0