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包,但是在搜索中一个包一个包的添加,在运行中会出现版本不匹配的问题,各种纠结。应当按如下的方式配置想着的依赖:

    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">

        4.0.0
        
            3.0.3
        
     
        
            net.roboconf
            parent
            1.0-SNAPSHOT
        
    
         net.roboconf
         roboconf-maven-plugin
         1.0-SNAPSHOT
         Roboconf :: Maven Plug-in
         maven-plugin
     
         
             UTF-8
             UTF-8
             3.2.2
         
     
         
             
                 org.apache.maven
                 maven-plugin-api
                 ${maven.version}
             
     
             
                 org.apache.maven.plugin-tools
                 maven-plugin-annotations
                 3.3
                 provided
             
     
             
                 net.roboconf
                 roboconf-core
                 ${project.version}
             
     
             
             
                 org.apache.maven.plugin-testing
                 maven-plugin-testing-harness
                 3.2.0
                 test
             
     
             
                 org.apache.maven
                 maven-aether-provider
                 ${maven.version}
                 test
             
     
             
                 org.apache.maven
                 maven-core
                 ${maven.version}
                 test
             
     
             
                 org.apache.maven
                 maven-compat
                 ${maven.version}
                 test
             
     
             
                 org.apache.maven
                 maven-model
                 ${maven.version}
                 test
             
             
         
         
             
                 
                     org.apache.maven.plugins
                     maven-plugin-plugin
                     3.3
                     
                         roboconf
                     
                 
             
         
     
    

在这个实例中使用的版本是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()这行其实出现了问题,所以就又回到原来的老路上。但是结合昨天查询到的其它的文章:

  • Unit Testing GMavenPlus Groovy Mojos - project.basedir not being expanded
  • Maven Plugin Harness - Maven - Apache Software Foundation

只要把测试用例中的代码修改为:
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文件如下:

    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">

        4.0.0
        
            3.0.3
        
    
        net.roboconf.test
        this-is-for-test-only
        1.0-SNAPSHOT
        This is for Test ONLY
        roboconf-app
    
        
            
                
                    net.roboconf
                    roboconf-maven-plugin
                    ${project.version}
                    true
                    
                
            
        
    
    

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

  • Maven – Guide to Developing Java Plugins
  • Maven – Mojo API Specification
    再说明一点,这两个地址都是Maven官网的地址,在正常访问Maven官网时,有些页面只能左边的导航部分,正文显示不出来。但是在F墙后显示是正常的,这点要注意。

你可能感兴趣的:(Maven Plugin(Mojo)开发中单元测试备忘)