如何在测试范围内使用m2e(Eclipse / Maven)运行命令行程序,并具有测试依赖性?

时间:2014-09-14 01:57:12

标签: java eclipse maven testing m2eclipse

我无法使用m2e插件运行java应用程序(static void main)。我通过普通的eclipse向导创建了一个多模块项目。看起来似乎一个模块的测试目录中的代码在运行时无法引用另一个模块的测试目录中的代码(编译工作正常)。

版本信息

  • Eclipse = Luna,Build 4.4.0,Build id 20140612-0600
  • m2e = 1.5.0.20140606-0033

我创建了一个非常简单(并且做作)的例子来演示我的问题。请轻松告诉我这段代码的无意义。另外,请原谅我这里的冗长。可悲的是,maven的问题几乎需要它。


这是项目目录结构:

--Project Explorer
 |--animals/
   |--src/test/java/
     |--com.example.problem.animals
       |--Animal.java
   |--JRE System Library [JavaSE-1.8]
   |--src/
   |--target/
   |--pom.xml
 |--dogs/
   |--src/test/java/
     |--com.example.problem.animals
       |--Beagle.java
   |--JRE System Library [JavaSE-1.8]
   |--Maven Dependencies
     |--animals/
   |--src/
   |--target/
   |--pom.xml
 |--parent/
   |--animals/
   |--dogs/
   |--src/
   |--pom.xml

父模块pom.xml:

<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.problem</groupId>
  <artifactId>parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>Parent</name>
  <description>Parent module for example project.</description>

  <modules>
    <module>animals</module>
    <module>dogs</module>
  </modules>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

动物模块pom.xml:

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

  <parent>
    <groupId>com.example.problem</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>animals</artifactId>

  <name>Animals</name>
  <description>Module to hold common animal code.</description>
</project>

狗模块pom.xml:

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

  <parent>
    <groupId>com.example.problem</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>dogs</artifactId>

  <name>Dogs</name>
  <description>Module to hold dog specific code.</description>

  <dependencies>
    <dependency>
      <groupId>com.example.problem</groupId>
      <artifactId>animals</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

这里的想法是用@Animal注释Beagle对象。注释位于&#34; animals&#34;的测试目录下,而我们的java runnable类Beagle位于&#34; dogs&#34;的测试目录下。

Animal.java:

package com.example.problem.animals;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Simple annotation to denote an animal.
 * 
 * @author Rich - created 03/Sep/2014
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Animal {
  String noise();
}

Beagle.java:

package com.example.problem.animals;

/*
 * Runnable java class that simply prints the animal noise for Beagle to the console.
 *
 * @author Rich - created 03/Sep/2014
 */
@Animal(noise = "Woof!")
public class Beagle {
  public static void main(String[] args) {
    Animal animal = Beagle.class.getAnnotation(Animal.class);
    System.out.println(animal.noise());
  }
}

为了运行Beagle类,我使用eclipse向导创建了一个新的运行配置。配置类型是&#34; Maven Build&#34;。 &#34; JRE&#34; tab有&#34; Runtime JRE&#34;设置为&#34;工作区默认JRE(jre1.8.0_20)&#34;。以下设置在&#34; Main&#34;上进行。配置选项卡:

  • &#34;基本目录&#34;字段设置为&#34; $ {workspace_loc:/ dogs}&#34;
  • &#34;目标&#34; field设置为&#34; exec:java&#34;
  • &#34;配置文件&#34;字段设置
  • &#34;用户设置&#34;字段设置
  • &#34;离线&#34;,&#34;更新快照&#34;,&#34;调试输出&#34;,&#34;跳过测试&#34;和&#34;非递归& #34;复选框已选中
  • &#34;解决Workspace工件问题&#34;复选框 已选中
  • 添加的参数
    • &#34; exec.mainClass&#34;设置为&#34; com.example.problem.animals.Beagle&#34;
    • &#34; exec.classpathScope&#34;设置为&#34; test&#34;
  • &#34; Maven Runtime&#34;被设置为&#34; EMBEDDED(3.2.1 / 1.5.0.20140605-2032)&#34;

运行此配置最终会失败并产生以下控制台输出:

[INFO] Scanning for projects...
[INFO] 
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Dogs 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ dogs ---
[WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6.
[WARNING] 
java.lang.reflect.InvocationTargetException
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
  at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NoClassDefFoundError: com/example/problem/animals/Animal
  at com.example.problem.animals.Beagle.main(Beagle.java:6)
  ... 6 more
Caused by: java.lang.ClassNotFoundException: com.example.problem.animals.Animal
  at java.net.URLClassLoader$1.run(Unknown Source)
  at java.net.URLClassLoader$1.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.net.URLClassLoader.findClass(Unknown Source)
  at java.lang.ClassLoader.loadClass(Unknown Source)
  at java.lang.ClassLoader.loadClass(Unknown Source)
  ... 7 more
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.282 s
[INFO] Finished at: 2014-09-13T18:25:51-08:00
[INFO] Final Memory: 9M/155M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.3.2:java (default-cli) on project dogs: An exception occured while executing the Java class. null: InvocationTargetException: com/example/problem/animals/Animal: com.example.problem.animals.Animal -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

使用&#34; Debug Output&#34;运行配置后设置,我在控制台中挖了几行,发现了以下有趣的内容:

[DEBUG] Configuring mojo 'org.codehaus.mojo:exec-maven-plugin:1.3.2:java' with basic configurator -->
[DEBUG]   (f) arguments = []
[DEBUG]   (f) classpathScope = test
[DEBUG]   (f) cleanupDaemonThreads = true
[DEBUG]   (f) daemonThreadJoinTimeout = 15000
[DEBUG]   (f) includePluginDependencies = false
[DEBUG]   (f) includeProjectDependencies = true
[DEBUG]   (f) keepAlive = false
[DEBUG]   (f) killAfter = 1
[DEBUG]   (f) localRepository =        id: local
...
[DEBUG] Project Dependencies will be included.
[DEBUG] Collected project artifacts [com.example.problem:animals:jar:0.0.1-SNAPSHOT:compile]
[DEBUG] Collected project classpath [C:\Users\cairnsjr13\workspace\parent\dogs\target\test-classes, C:\Users\cairnsjr13\workspace\parent\dogs\target\classes]
[DEBUG] Adding to classpath : file:/C:/Users/cairnsjr13/workspace/parent/dogs/target/test-classes/
[DEBUG] Adding to classpath : file:/C:/Users/cairnsjr13/workspace/parent/dogs/target/classes/
[DEBUG] Adding project dependency artifact: animals to classpath

我很困惑的原因是,它似乎试图包含动物&#34;依赖。我怀疑它包括主依赖,而不是测试依赖。所以...在这个极长的蜿蜒信息转储之后......有没有人知道如何让eclipse(m2e)执行这种情况?我已经正确配置它来处理测试测试编译依赖项,但是在我的生命中不能让运行时依赖项工作。

2 个答案:

答案 0 :(得分:2)

exec.classpathScope设置为test会将已执行模块的测试类添加到类路径中,但不会将依赖项的测试类添加到类路径中。如调试输出中所示,它添加了dogs模块的测试类,但添加animals的测试类:

[DEBUG] Adding to classpath : file:/C:/Users/cairnsjr13/workspace/parent/dogs/target/test-classes/

为了依赖animals的测试类,您需要按照this link中的说明指定maven-jar-plugin目标,为其配置test-jar。< / p>

<强>动物

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>test-jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

然后更新dogsanimals的依赖关系以获得测试范围,如下所示:

<强>狗

<dependencies>
    <dependency>
        <groupId>com.example.problem</groupId>
        <artifactId>animals</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>test-jar</type> 
        <scope>test</scope>
    </dependency>
</dependencies>

将此配置添加install animals模块到您当地的Maven存储库后。这将在您的本地仓库中创建一个Jar,其中包含模块的测试类,特别是Animal类,以及为主类创建的普通Jar。您可以从命令行执行安装,也可以右键单击animals项目,然后选择运行方式 - &gt; Maven安装

然后在Eclipse中启动相同的运行配置,但使用“Resolve Workspace artifacts”复选框取消选中,以便从本地Maven存储库中解析测试工件。

在重现您的场景时,我注意到的奇怪之处在于,如果我添加了上述所有Maven配置(maven-jar-plugin和测试范围的依赖项),但我保留了“Resolve Workspace artifacts”复选框,m2eclipse无法在工作空间中解析测试Jar,即使目标文件夹包含Jar并且项目已刷新/更新。我觉得这是插件本身的一个错误,特别是在解析使用test-jar目标配置的工作区测试Jar 依赖时。

答案 1 :(得分:1)

经过大量的渐进式更改和反复试验,我已经找到了如何使其发挥作用。这种方法的好处在于,您仍然可以在动物项目中积极开发,而无需每次都将其作为测试罐导出。 &lt;依赖&gt; tag具有必须设置的type属性。狗pom.xml文件然后变成:

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

  <parent>
    <groupId>com.example.problem</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>dogs</artifactId>

  <name>Dogs</name>
  <description>Module to hold dog specific code.</description>

  <dependencies>
    <dependency>
      <groupId>com.example.problem</groupId>
      <artifactId>animals</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <type>test-jar</type>
    </dependency>
  </dependencies>
</project>

执行原始运行配置会产生以下输出:

[INFO] Scanning for projects...
[INFO] 
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Dogs 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ dogs ---
[WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6.
Woof!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.310 s
[INFO] Finished at: 2014-09-21T13:53:21-08:00
[INFO] Final Memory: 9M/155M
[INFO] ------------------------------------------------------------------------

这里有几点需要注意。

不需要将scope属性设置为test以使其运行。添加&lt; scope&gt;测试&lt; / scope&gt;对依赖项的标记将导致在非测试范围中省略依赖项。由于我们在测试范围内运行并不重要。

这种方法不包括对动物主要代码的依赖。在原始问题的示例中,这并不重要,因为没有主代码源目录。如果动物的测试代码依赖于动物的主要代码,则必须在狗中添加额外的依赖关系才能选择它。以下是dog pom.xml文件在这种情况下的样子:

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

  <parent>
    <groupId>com.example.problem</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>dogs</artifactId>

  <name>Dogs</name>
  <description>Module to hold dog specific code.</description>

  <dependencies>
    <!-- Including both dependencies for jar and test-jar to get main src included. -->
    <dependency>
      <groupId>com.example.problem</groupId>
      <artifactId>animals</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>com.example.problem</groupId>
      <artifactId>animals</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <type>test-jar</type>
    </dependency>
  </dependencies>
</project>