Maven Plugin(Mojo)開發(fā)中單元測試備忘

昨天準(zhǔn)備就現(xiàn)在開發(fā)中的問題寫一個(gè)Maven插件,完成一些代碼的自動生成。在好幾年前寫過幾個(gè)插件,這次重新找開看后,發(fā)現(xiàn)原來的都很簡單,所以都沒有在開發(fā)期間的進(jìn)行測試??紤]到這次寫的稍微復(fù)雜一些,如果每次修改到東西都要到目標(biāo)項(xiàng)目中進(jìn)行測試,那么效率太差了,所以準(zhǔn)備先把插件開發(fā)中相關(guān)的單元測試搞定。

誰成想,這樣一下子發(fā)現(xiàn)了一個(gè)大坑。過程是這樣的:

  • 首先在Maven的官網(wǎng)上查找相關(guān)的文檔,發(fā)現(xiàn)原來codehaus這個(gè)組織已經(jīng)關(guān)閉了,原來他們開發(fā)的很多插件都轉(zhuǎn)移到各處。
  • 官司網(wǎng)上的文檔對測試這塊講解很不清楚,如果按官網(wǎng)上的說明([How To Use Maven Plugin Testing Harness?]),過程中出現(xiàn)了幾個(gè)問題:
    • 首先在測試時(shí)會報(bào)MavenExecuteResult、MavenSession、MavenResporitory等各種對象不存在的問題
    • 官網(wǎng)的例子使用的是比較老的繼承AbstractMojoTestCase的方法,當(dāng)解決了依賴的問題后,會發(fā)現(xiàn)如果在Mojo中使用類似${project.build.directory}等expression時(shí),無法進(jìn)行值的引用。
    • 這期間還發(fā)生了,在Mojo中使用@Parameter時(shí)在會出現(xiàn)

[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]

幸好有g(shù)oogle在(真難以相像如果使用百度會是一個(gè)怎么樣的結(jié)果),經(jīng)過長時(shí)間各種搜索發(fā)現(xiàn)了一篇最有用的文章Write Unit Tests for a Maven plug-in[感謝作者幫我解決了這個(gè)大問題],它解決了基本所有的問題,下面摘錄一些要點(diǎn):

  • 上面問題中的第一個(gè),也就是各種對象不存在的問題,主要原因是在測試中需要使用若干個(gè)關(guān)聯(lián)的jar包,但是在搜索中一個(gè)包一個(gè)包的添加,在運(yùn)行中會出現(xiàn)版本不匹配的問題,各種糾結(jié)。應(yīng)當(dāng)按如下的方式配置想著的依賴:
    <?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>
    

在這個(gè)實(shí)例中使用的版本是3.2.2,我自己經(jīng)過測試,發(fā)現(xiàn)3.2.3也是可以使用的。另外,由于在Mojo中會使用如MavenProject這樣的對象,這樣的類差不多都在maven-core中,如果在compile時(shí)發(fā)現(xiàn)類找不到,可以將依賴中下面幾個(gè)scopetest的修改為provided。

  • 在測試時(shí),最早使用的是junit 3.8.1,所以使用的基類是AbstractMojoTestCase,這個(gè)類有很多問題,諸如在前面列舉的。所以,最好使用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();
        }
    }
    

由于 走過了一些彎路,所以上面的代碼是今天早上起床時(shí)才突然想到的,因?yàn)樵瓉硪黄鹗褂肁bstractMojoTestCase,按那個(gè)思路在解決問題。今天早上突然回想起這個(gè)文章的這后半部分,說實(shí)在的,在剛看到文章時(shí),this.rule.lookupMojo()這行其實(shí)出現(xiàn)了問題,所以就又回到原來的老路上。但是結(jié)合昨天查詢到的其它的文章:

只要把測試用例中的代碼修改為:
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的問題了。

  • 最后,項(xiàng)目的結(jié)構(gòu)應(yīng)當(dāng)諸如:
    + 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>
    

最后,以下是幾個(gè)Mojo開發(fā)中有用的鏈接,備忘:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,667評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,832評論 18 139
  • 我jdk版本是1.7.0_95,在網(wǎng)上查了一下1.7屬于java7maven3.3+版本都支持java7,所以我使...
    liangxifeng833閱讀 1,282評論 0 2
  • Maven編譯代碼的相關(guān)命令 第一、main目錄下的主代碼編寫完畢后,使用Maven進(jìn)行編譯,在項(xiàng)目根目錄下運(yùn)行命...
    加油小杜閱讀 1,229評論 0 2
  • 使用指導(dǎo) 如何添加外部依賴jar包 在Maven工程中添加依賴jar包,很簡單,只要在POM文件中引入對應(yīng)的<de...
    靜默虛空閱讀 2,818評論 0 13
  • 寫作要求 堅(jiān)持寫作第9天~主題寫作 閱讀應(yīng)該是與寫作并行的,閱讀是寫作的基礎(chǔ),所以,大家要完成的任務(wù)是讀一本自己曾...
    Albert陳凱閱讀 328評論 0 0