2015-06-15 37 views
0

我目前正在嘗試使用GMavenPlus編寫Maven插件(謝謝@Keegan!)和Groovy 2.4.3。簡而言之,該插件解析SQL DDL的目錄並從這些解析的DDL中生成輸出單元測試GMavenPlus Groovy Mojos - project.basedir未擴展

當在完整的消費項目中構建,導入和運行時,Mojo本身工作得很好。 Horrah!

問題出在單元測試。當試圖對這個Mojo進行單元測試時,像${project.basedir}這樣的Maven POM變量並不是 擴展的,因此mojo失敗時會出現「File not found![$ {project.basedir}/src/test/resources/ddl]」錯誤。由於 您可以從該錯誤消息中看到,${project.basedir}作爲文字傳遞而不是展開。

我目前使用Maven Plugin Testing Harness(與固定依賴關係,請參閱this blog),JUnit 4.12和AssertJ 3.0.0作爲我的測試堆棧。

任何想法或特定的技巧,讓像project.basedir這樣的東西在單元測試中展開?

在此先感謝!

單元測試問題:

import edge.SqlToScalaMojo 
import org.junit.Before 
import org.junit.Test 

/** 
* Created by medge on 6/15/15. 
*/ 
class SqlToScalaMojoTest extends BaseMojoTest<SqlToScalaMojo> { 

    SqlToScalaMojo mojo 

    @Before 
    void setup() { 
     mojo = getMojo("parse-ddls") 
    } 

    @Test 
    void testMojoExecution() throws Exception { 
     assertThat mojo isNotNull() 

     mojo.execute() 
    } 
} 

BaseMojoTest.groovy(其實只是一個方便的基類):

import org.apache.maven.plugin.AbstractMojo 
import org.apache.maven.plugin.testing.MojoRule 
import org.junit.Rule 

/** 
* Base Test class for Mojo tests. Extends {@link org.assertj.core.api.Assertions} 
* 
* If a type is given to this class then the result of #getMojo() does not have to be cast, reducing the amount of code 
* to be written in the unit tests themselves. 
* 
* Created by medge on 6/5/15. 
*/ 
abstract class BaseMojoTest<T extends AbstractMojo> extends org.assertj.core.api.Assertions { 

    /** 
    * MojoRule used to lookup Mojos 
    */ 
    @Rule public MojoRule rule = new MojoRule() 

    /** 
    * Get a configured mojo using the default pom file. Calls #getMojo(goal, getPom()) implicitly 
    * 
    * @param goal Goal to look up 
    * @return T configured Mojo 
    */ 
    T getMojo(String goal) { 
     getMojo(goal, getPom()) 
    } 

    /** 
    * Get a configured mojo using the specified pom file 
    * 
    * @param goal Goal to look up 
    * @param pom POM file to use when configuring Mojo 
    * @return T configured Mojo 
    */ 
    T getMojo(String goal, File pom) { 
     T mojo = (T) rule.lookupMojo(goal, pom) 

     mojo 
    } 

    /** 
    * Default POM file if no custom path is given 
    */ 
    String defaultPomPath = "src/test/resources/plugin-config.xml" 

    /** 
    * Return a File reference containing the default POM file 
    * 
    * @return File 
    */ 
    File getPom() { 
     getPom(defaultPomPath) 
    } 

    /** 
    * Return a File reference containing the POM file found at the specified path. Implicitly asserts that the POM 
    * exists using <code>assertFile</code> 
    * 
    * @param path Path to user-defined POM (overrides the default if provided) 
    * @return File containing the specified POM. 
    */ 
    File getPom(String path) { 
     File _pom = getTestFile(path) 

     // Implicitly assert POM exists 
     assertFile(_pom) 

     // Then return the POM file 
     _pom 
    } 

    /** 
    * Convenience method to assert that a file is valid 
    * 
    * @param file File to validate 
    */ 
    static void assertFile(File file) { 
     assertThat file isNotNull() 
     assertThat file exists() 
    } 

    /** 
    * Get the current project's base directory. From {@link org.codehaus.plexus.PlexusTestCase} 
    * 
    * @return Base directory path 
    */ 
    static String getBaseDir() { 
     final String path = System.getProperty("basedir"); 

     path ?: new File("").getAbsolutePath(); 
    } 

    /** 
    * Return a test file from the src/test/resources directory. Assumes the base directory is src/test/resources so the 
    * src/test/resources prefix can be omitted from the path if desired 
    * 
    * @param path File path 
    * @return File 
    */ 
    static File getTestFile(String path) { 
     File testFile 

     if(path.indexOf("src/test/resources/") > -1) 
      testFile = getTestFile(getBaseDir(), path) 
     else 
      testFile = getTestFile(getBaseDir(), "src/test/resources/${path}") 

     testFile 
    } 

    /** 
    * Retrieve a test file from the given baseDir/path 
    * 
    * @param baseDir String base directory to look in 
    * @param path String path to the file desired 
    * @return File 
    */ 
    static File getTestFile(String baseDir, String path) { 
     new File(baseDir, path) 
    } 
} 

的魔咒本身主要POM文件:

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

    <groupId>edge</groupId> 
    <artifactId>parser-mojo</artifactId> 
    <version>0.0.3-SNAPSHOT</version> 
    <packaging>maven-plugin</packaging> 

    <properties> 
     <groovy.version>2.4.3</groovy.version> 
     <maven.version>3.3.3</maven.version> 
     <junit.version>4.12</junit.version> 
     <assertj.version>3.0.0</assertj.version> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>org.codehaus.groovy</groupId> 
      <artifactId>groovy-all</artifactId> 
      <version>${groovy.version}</version> 
     </dependency> 

     <!-- Test dependencies --> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>${junit.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.assertj</groupId> 
      <artifactId>assertj-core</artifactId> 
      <version>${assertj.version}</version> 
      <scope>test</scope> 
     </dependency> 


     <!-- Dependencies for Maven Mojos --> 
     <dependency> 
      <groupId>org.codehaus.plexus</groupId> 
      <artifactId>plexus-utils</artifactId> 
      <version>3.0.22</version> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.maven</groupId> 
      <artifactId>maven-core</artifactId> 
      <version>${maven.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.maven</groupId> 
      <artifactId>maven-artifact</artifactId> 
      <version>${maven.version}</version> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.maven</groupId> 
      <artifactId>maven-compat</artifactId> 
      <version>${maven.version}</version> 
     </dependency> 
     <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.4</version> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.maven.plugin-testing</groupId> 
      <artifactId>maven-plugin-testing-harness</artifactId> 
      <version>3.3.0</version> 
      <scope>test</scope> 
      <type>jar</type> 
     </dependency> 
    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.codehaus.gmavenplus</groupId> 
       <artifactId>gmavenplus-plugin</artifactId> 
       <version>1.5</version> 
       <executions> 
        <execution> 
         <goals> 
          <goal>addSources</goal> 
          <goal>addTestSources</goal> 
          <goal>generateStubs</goal> 
          <goal>compile</goal> 
          <goal>testGenerateStubs</goal> 
          <goal>testCompile</goal> 
          <goal>removeStubs</goal> 
          <goal>removeTestStubs</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-plugin-plugin</artifactId> 
       <version>3.4</version> 
       <configuration> 
        <!-- see http://jira.codehaus.org/browse/MNG-5346 --> 
        <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> 
       </configuration> 
       <executions> 
        <execution> 
         <id>generate-descriptor</id> 
         <goals> 
          <goal>descriptor</goal> 
         </goals> 
        </execution> 
        <execution> 
         <id>help-goal</id> 
         <goals> 
          <goal>helpmojo</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

在單元測試期間使用的測試POM:

<project> 
    <build> 
     <plugins> 
      <plugin> 
       <groupId>edge</groupId> 
       <artifactId>parser-mojo</artifactId> 
       <version>0.0.3-SNAPSHOT</version> 
       <configuration> 
        <template>${project.basedir}/src/test/resources/sample.template</template> 
        <inputDir>${project.basedir}/src/test/resources/ddl</inputDir> 
        <outputDir>${project.basedir}/src/test/resources/generated/</outputDir> 
       </configuration> 
       <executions> 
        <execution> 
         <phase>generate-resources</phase> 
         <goals> 
          <goal>parse-ddls</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

謝謝!

回答

2

找到了我自己問題的答案。如果有其他人正在尋找同樣的問題,請在這裏發帖。

首先,我遇到了關於@Parameter註釋的Mojo本身的另一個問題。以下:

@Parameter(defaultValue = "${project.basedir}/src/main/resources") 
String inputDir 

將產生一個錯誤,因爲Groovy編譯器將Maven的前拿起串"${project.basedir}/src/main/resources"。然後它將進行評估並將其轉換爲GString。這會產生一個錯誤,因爲註釋需要一個java.lang.String,但它會得到java.lang.Object

@Keegan在another question中指出的解決方案是使用單引號而不是雙引號:

@Parameter(defaultValue = '${project.basedir}/src/main/resources') 
String inputDir 

Groovy編譯器不會評價字符串和Maven會從那裏拿起

接下來,關於默認值的單元測試時不被讀取原來的問題。罪魁禍首是BaseMojoTest中的這種方法。常規:

T getMojo(String goal, File pom) { 
    T mojo = (T) rule.lookupMojo(goal, pom) 

    mojo 
} 

具體來說,這一部分:

rule.lookupMojo(goal, pom) 

lookupMojo上MojoRule 評估參數註解的默認值。它期望所有可能的參數都存在於測試POM文件中。快速潛入源MojoRule和我發現了一種方法來解決它:

/** 
* Get a configured mojo using the specified pom file 
* 
* @param goal Goal to look up 
* @param pom POM file to use when configuring Mojo 
* @return T configured Mojo 
*/ 
T getMojo(String goal, File pom) { 
    T mojo = (T) rule.lookupConfiguredMojo(getMavenProject(pom), goal) 

    mojo 
} 

/** 
* Method to handle creating a MavenProject instance to create configured Mojos from 
* @param pom File to POM file containing Mojo config 
* @return MavenProject 
*/ 
MavenProject getMavenProject(File pom) { 
    // create the MavenProject from the pom.xml file 
    MavenExecutionRequest request = new DefaultMavenExecutionRequest() 
    ProjectBuildingRequest configuration = request.getProjectBuildingRequest() 
      .setRepositorySession(new DefaultRepositorySystemSession()) 
    MavenProject project = rule.lookup(ProjectBuilder.class).build(pom, configuration).getProject() 

    project.basedir = new File(getBaseDir()) 

    // Implicit assert 
    assertThat project isNotNull() 

    // And return 
    project 
} 

getMavenProject()方法是在MojoRule#readMavenProject()找到的代碼的輕微變化,改變以引用MojoRule和我的getBaseDir的定義() 。由此方法生成的Mojos現在正確評估@ Parameter的defaultValue!我覺得getMavenProject()可能會更有效率(而不是每次創建一個MavenProject),但現在就足夠了。

一件事

您可能已經注意到從getMavenProject()方法這一行:

project.basedir = new File(getBaseDir()) 

這非常惱人的小黑客是必要的,因爲在創建MavenProject對象時:

MavenProject project = rule.lookup(ProjectBuilder.class).build(pom, configuration).getProject() 

$ {project.basedir}實際上成爲的基礎代碼在單元測試中使用的測試POM文件。如果像我一樣,在src/test/resources中有一個測試POM,那麼basedir就會變成類似/Users/medge/.../src/test/resources。人機工程學,當@Parameter註釋使用$ {} project.basedir展開,如:

@Parameter(defaultValue='${project.basedir}/src/main/resources') 
String inputDir 

當從單元測試跑,inputDir將解析爲/Users/medge/.../src/test/resources/src/main/resources

微妙的東西可以發覺你..

希望這對別人有幫助!

0

我有一個類似的問題,但我從配置中插入路徑,發現不同的溶劑。

我改變了測試項目POM這樣:

<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/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.example.maven.plugin.MyPlugin</groupId> 
    <artifactId>testProject</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 
    <name>Test MyPlugin</name> 

    <dependencies> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>3.8.1</version> 
      <scope>test</scope> 
     </dependency> 
    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <artifactId>myPlugin-maven-plugin</artifactId> 
       <configuration> 
        <testDirectory>${basedir}\src\test\resources\testDir</testDirectory> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

所不同的是在testDirectory。雖然

<testDirectory>${project.basedir}\src\test\resources\testDir</testDirectory>

計算結果爲相同的字符串,這

<testDirectory>${basedir}\src\test\resources\testDir</testDirectory>

評估爲具體路徑上的文件系統C:\Development\projects\..\src\test\resources\testDir