如何阻止Maven的验证阶段重建工件?

时间:2010-12-02 00:19:48

标签: java maven-2 continuous-integration hudson continuous-deployment

想象一下使用Maven构建的Java项目,我有:

  • 一些快速运行的单元测试:
    • 开发人员应该在提交之前运行
    • 我的CI服务器(Hudson,FWIW)应该在检测到新提交时运行,在发生故障时提供几乎即时反馈
  • 一些慢速运行的自动验收测试:
    • 开发人员可以选择运行,例如重现和修复失败
    • 我的CI服务器应在成功运行单元测试后运行

这似乎是一个典型的场景。目前,我正在运行:

  • 单元在“测试”阶段进行测试
  • “验证”阶段的验收测试

配置了两个CI作业,两者都指向项目的VCS分支:

  1. “Commit Stage”,运行“mvn package”(编译和单元测试代码,构建工件),如果成功,则触发:
  2. “自动验收测试”,运行“mvn verify”(设置,运行和拆除验收测试)
  3. 问题在于作业2单元测试并重新构建被测工件(因为验证阶段会自动调用包阶段)。由于几个原因(重要性降低),这是不可取的:

    • 作业2创建的工件可能与作业1创建的工件不同(例如,如果在此期间有新的提交)
    • 将反馈循环延长到进行提交的开发人员(即他们需要更长时间才能发现他们破坏了构建)
    • 在CI服务器上浪费资源

    所以我的问题是,如何配置作业2以使用作业1创建的工件?

    我意识到我可以只有一个运行“mvn verify”的CI作业,它只会创建一次工件,但是我想要上面描述的单独CI作业以实现Farley风格的部署管道


    如果它对任何人有帮助,这里是接受答案中“项目2”的完整Maven 2 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/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example.cake</groupId>
        <artifactId>cake-acceptance</artifactId>
        <version>1.0</version>
        <packaging>jar</packaging>
        <name>Cake Shop Acceptance Tests</name>
        <description>
            Runs the automated acceptance tests for the Cake Shop web application.
        </description>
        <build>
            <plugins>
                <!-- Compiler -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.1</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
                <!-- Suppress the normal "test" phase; there's no unit tests -->
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.5</version>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
                <!-- Cargo (starts and stops the web container) -->
                <plugin>
                    <groupId>org.codehaus.cargo</groupId>
                    <artifactId>cargo-maven2-plugin</artifactId>
                    <version>1.0.5</version>
                    <executions>
                        <execution>
                            <id>start-container</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>start</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>stop-container</id>
                            <phase>post-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!-- Don't wait for CTRL-C after starting the container -->
                        <wait>false</wait>
    
                        <container>
                            <containerId>jetty7x</containerId>
                            <type>embedded</type>
                            <timeout>20000</timeout>
                        </container>
    
                        <configuration>
                            <properties>
                                <cargo.servlet.port>${http.port}</cargo.servlet.port>
                            </properties>
                            <deployables>
                                <deployable>
                                    <groupId>${project.groupId}</groupId>
                                    <artifactId>${target.artifactId}</artifactId>
                                    <type>war</type>
                                    <properties>
                                        <context>${context.path}</context>
                                    </properties>
                                </deployable>
                            </deployables>
                        </configuration>
                    </configuration>
                </plugin>
                <!-- Failsafe (runs the acceptance tests) -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <version>2.6</version>
                    <executions>
                        <execution>
                            <id>integration-test</id>
                            <goals>
                                <goal>integration-test</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>verify</id>
                            <goals>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <includes>
                            <include>**/*Test.java</include>
                        </includes>
                        <skipTests>false</skipTests>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <dependencies>
                <!-- Add your tests' dependencies here, e.g. Selenium or Sahi,
                    with "test" scope -->
            <dependency>
                <!-- The artifact under test -->
                <groupId>${project.groupId}</groupId>
                <artifactId>${target.artifactId}</artifactId>
                <version>${target.version}</version>
                <type>war</type>
            </dependency>
        </dependencies>
        <properties>
            <!-- The artifact under test -->
            <target.artifactId>cake</target.artifactId>
            <target.version>0.1.0-SNAPSHOT</target.version>
            <context.path>${target.artifactId}</context.path>
            <http.port>8081</http.port>
            <java.version>1.6</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    </project>
    

    请注意,即使这个“测试”项目没有创建工件,它也必须使用某种打包(我在这里使用“jar”),否则在验证阶段不会运行任何测试。

5 个答案:

答案 0 :(得分:4)

尝试两个maven项目。第一个包含构建和单元测试。您可以在本地存储库中安装工件。第二个作业运行第二个maven项目,该项目将第一个项目的工件声明为依赖项并运行功能测试。

不确定我刚才描述的场景是否可行,但我认为是。

为了快速改进,您可以使用-Dmaven.test.skip=true绕过单元测试。如果您将scm中代码的修订号传递给第二个作业,您应该可以签出相同的源代码。

您还可以查看克隆工作区SCM插件。这可能会为您提供一些额外的选择。

答案 1 :(得分:1)

我知道它已经很长一段时间了,但这是很好的索引,所有答案都没有做到,但我发现了一些有用的东西:

mvn failsafe:integration-test

直接运行测试,无需完成构建项目的所有中间步骤。您可能希望在其后添加failsafe:verify

答案 2 :(得分:0)

答案 3 :(得分:0)

您可以定义将用于仅执行集成测试的Maven配置文件。我做了很多。

这样的事情:

<profiles>
    <profile>
        <id>integration</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId><version>2.17</version>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId><version>2.4</version>
                    <configuration>
                        <outputDirectory>/tmp</outputDirectory>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

您可以使用以下方式调用此方法:

mvn verify -Pintegration

不幸的是,不能跳过WAR插件,但是你可以把它的输出发送到某个地方(我使用过/ tmp)。如果你真的想节省毫秒数,你也可以让它忽略网络资源(除了web.xml,没有它就不会工作)。

您还可以使用配置文件跳过您可能正在运行的任何其他插件,例如程序集插件,Cobertura,PMD等。

答案 4 :(得分:0)

仅执行集成测试(as suggested here)的Maven配置文件是不够的。您还需要确保 maven-compiler-plugin 的配置具有 useIncrementalCompilation = false 。以这种方式运行配置文件不会自动重新编译,例如:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.3</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <useIncrementalCompilation>false</useIncrementalCompilation>
    </configuration>
</plugin>