Maven - 在JUnit测试之前将webapp部署到tomcat

时间:2013-06-05 08:44:04

标签: maven tomcat junit maven-2 tomcat7

我有提供网络服务的webapp。我想用SoapUI执行JUnit测试,以检查此服务是否正常工作 但是要测试Web服务应用程序必须部署到我的Tomcat 7服务器。

我不知道如何配置maven来构建war,然后将其部署到tomcat(理想情况下:为此运行单独的tomcat实例)然后运行JUnit测试。
我将不胜感激。

我正在使用maven 2.2.1

3 个答案:

答案 0 :(得分:117)

关于如何使用Maven处理此类集成测试,有许多思想流派。

我应该指出,当您将应用程序部署到应用程序服务器时,您不再需要进行单元测试。因为整个应用程序正在一个容器中部署,所以您正在测试这两个组件的集成。

现在使用JUnit运行集成测试没有任何问题(尽管您可能遇到一些限制,例如单元测试不应该关心顺序个别测试 - 假设你正确地编写它们 - 所以JUnit 通过不保证任何执行顺序强制执行 ...在Java 1.7之前,执行顺序是由于测试方法的顺序意外隐含的class,但它不是JUnit合同的一部分...有些人切换到其他测试框架进行集成测试,例如TestNG,如果他们找到单元测试焦点 JUnit正在妨碍他们的测试开发)

要记住的关键点是Maven生命周期使用test阶段来执行单元测试。

当谈到集成测试时,有两种(一半)思想流派以正确的方式处理Maven的测试。

学校1 - 故障安全和integration-test/verify

这种思想使用package之后的阶段来启动容器,运行集成测试,拆除容器,最后检查测试结果并在测试失败的情况下使构建失败。 / p>

永远无法运行mvn integration-test,因为只要您认为要输入mvn integration-test实际上想要输入mvn verify,就不能正确拆卸容器(哦,看看) ,它更短更容易输入...奖金)

因此,您可以执行以下操作:

对于额外的布朗尼点,您可以使用绑定到validate阶段的build-helper-maven-plugin:reserve-network-port来确保测试服务器在未使用的网络端口上启动,然后对测试资源使用资源过滤来传递移植到测试或使用通过systemPropertyVariables传递的系统属性来使测试可用的端口号。

优点

  • 清理Maven构建
  • 如果测试失败,则无法发布项目
  • 如果测试速度太慢而无法运行每个版本,可以将集成测试移动到单独的配置文件中(按惯例称为run-its)。

缺点

  • 很难从IDE运行测试。所有集成测试都在IT开始/结束,而Maven知道使用Surefire在Test中开始/结束测试,并使用Failsafe在IT中运行测试开始/结束,您的IDE可能没有& #39;吨。此外,您的IDE不会为您启动容器,因此您必须手动执行大量工作才能实际运行测试。
  • 调试测试可能需要附加两个调试器,例如:一个调试在容器中运行的应用程序,另一个调试到debug the test cases

    mvnDebug -Dmaven.failsafe.debug=true verify
    
  • 将您的测试与Maven构建过程相结合。

学校2 - 单独的模块

这种思想将集成测试移动到一个独立的模块中,该模块依赖于war模块,并使用例如wargenerate-test-resources复制到测试资源中。 dependency:copy-dependencies绑定到war阶段,加上Tomcat7依赖关系以进行测试。

测试用例本身使用embedded mode

启动Tomcat7容器

优点

  • 测试可以在IDE中运行
  • 集成测试与单元测试分开,因此要求IDE运行所有测试不会启动较慢的测试

缺点

  • 只有在超过package阶段时才会重建mvn clean package工件,因此,在使用IDE时,您需要定期运行至少war以刷新测试中的代码。
  • 集成测试的失败不会破坏war模块的构建,因此您最终可能会释放损坏的src/it工件,然后让集成测试模块的reactor构建失败。有些人通过在{{1}}内使用集成测试模块并使用Maven Invoker插件来运行测试来抵消这个问题......虽然这提供了较差的IDE集成,所以我不推荐这一行。
  • 很难从Maven获得综合测试报告。
  • 必须在测试用例中自行编码容器启动/停止。

School 2.5 - 测试用例启动自己的Tomcat7服务器时出现故障

这是两种方法的混合。

您使用Failsafe执行测试,但测试本身负责启动和停止您要测试的Tomcat7容器。

优点

  • 不必在Maven pom中配置服务器启动/停止
  • IDE可以安全地运行所有测试(虽然集成测试可能会更慢,但您可能不想运行它们,但它们并不像它们都会失败,除非测试失败)
  • 更容易从IDE调试测试(只有一个要附加的进程,IDE通常可以通过提供特殊的测试运行程序来轻松调试测试)

缺点

  • 必须在测试用例中自行编写容器启动/停止

我希望上述内容可以帮助您了解您的选择。可能还有其他一些调整,但总的来说,上面被认为是目前与Maven进行集成测试的最佳实践。

答案 1 :(得分:1)

@Stephen Connolly - 你上面的回答非常好。我想我会开始为你所谓的School 1回复显示一个完整的配置。

此配置:

  • 与集成测试分开运行单元测试。它在单元测试和集成测试扩展的根类上使用@Category注释。
  • 在集成测试之前,通过查找开放端口启动依赖应用程序(在运行时作为maven依赖项加载),通过查找开放端口
  • 在集成测试之后,它会删除依赖的应用程序

其他内容就像如何仅在依赖应用程序上设置某些系统属性一样。

到目前为止,这种配置工作真棒..

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>1.9.1</version>
            <executions>
                <execution>
                    <id>reserve-network-port</id>
                    <goals>
                        <goal>reserve-network-port</goal>
                    </goals>
                    <phase>pre-integration-test</phase>
                    <configuration>
                        <portNames>
                            <portName>tomcat.maven.http.port</portName>
                        </portNames>
                    </configuration>
                </execution>
                <execution>
                    <id>get-local-ip</id>
                    <goals>
                        <goal>local-ip</goal>
                    </goals>
                    <configuration>
                        <!-- if not given, 'local.ip' name is used -->
                        <localIpProperty>local.ip</localIpProperty>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <!-- http port from reserve-network-port-plugin-->
                <port>${tomcat.maven.http.port}</port>
                <!-- application path always starts with /-->
                <path>/</path>
                <webapps>
                    <webapp>
                        <groupId>com.company.other.app</groupId>
                        <artifactId>web-rest</artifactId>
                        <version>1.0.1-SNAPSHOT</version>
                        <type>war</type>
                        <contextPath>/webapi-loopback</contextPath>
                        <asWebapp>true</asWebapp>
                    </webapp>
                </webapps>
            </configuration>
            <executions>
                <execution>
                    <id>start-server</id>
                    <configuration>
                        <fork>true</fork>
                        <skip>${skipTests}</skip>
                        <systemProperties>
                            <spring.profiles.active>test,h2</spring.profiles.active>
                        </systemProperties>
                    </configuration>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>stop-server</id>
                    <configuration>
                        <skip>${skipTests}</skip>
                    </configuration>
                    <phase>post-integration-test</phase>
                    <goals>
                        <goal>shutdown</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19</version>
            <configuration>
                <excludedGroups>com.company.app.service.IntegrationTestRootClassAnnotatedWithAtCategory</excludedGroups>
            </configuration>
            <executions>
                <execution>
                    <id>unit-test</id>
                    <phase>test</phase>
                    <goals>
                        <goal>test</goal>
                    </goals>
                    <configuration>
                        <argLine>-Xmx1024m -XX:MaxPermSize=256m @{jacocoArgLine}</argLine>
                        <excludedGroups> com.company.app.service.IntegrationTestRootClassAnnotatedWithAtCategory </excludedGroups>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.18</version>
            <dependencies>
                <dependency>
                    <groupId>org.apache.maven.surefire</groupId>
                    <artifactId>surefire-junit47</artifactId>
                    <version>2.18</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <id>start-integration-test</id>
                    <phase>integration-test</phase>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                    <configuration>
                        <argLine>-Xmx1024m -XX:MaxPermSize=256m @{jacocoArgLine}</argLine>
                        <groups>com.company.app.IntegrationTestRootClassAnnotatedWithAtCategory</groups>
                        <includes>
                            <include>**/*.java</include>
                        </includes>
                        <systemPropertyVariables>
                            <program.service.url>
                                http://${local.ip}:${tomcat.maven.http.port}/webapi-loopback
                            </program.service.url>
                        </systemPropertyVariables>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

答案 2 :(得分:0)

Stephen Connolly解释说,没有直接的方法来配置它。我将解释如何使用failsafe插件解决这个问题。在maven生命周期中可以测试类型的测试。单元测试其中一个,另一个是集成测试。单元测试可以在maven生命周期的测试阶段运行。当您想要进行集成测试时,可以在验证阶段完成。如果您想知道单元测试和集成测试之间的区别,那么这是一个good one。默认情况下,单元测试类应为 ***/*Test.java **/*TestCase.java 此格式。故障安全插件将查找 **/IT*.java **/*IT.java **/*ITCase.java

这是一个例子。 enter image description here

这里我有一个单元测试类和一个集成测试类。现在我要解释一下,看起来应该是maven pom.xml。 maven配置的构建部分应该如下所示。

<build>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
                <warName>${name}</warName>
                <outputDirectory>/home/jobs/wso2/wso2as-5.3.0/repository/deployment/server/webapps</outputDirectory>
                <goal>
                </goal>
            </configuration>
        </plugin>

        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.12.4</version>
            <executions>
                <execution>
                    <id>integration-test</id>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

在部署Web应用程序(war文件)之前运行单元测试。但集成测试在验证阶段运行。我希望在这个阶段你的要求得到满足。