web-dev-qa-db-ja.com

Maven-JUnitテストの前にWebアプリケーションをTomcatにデプロイする

Webサービスを提供するwebappがあります。 SoapUIでJUnitテストを実行して、このサービスが適切に機能しているかどうかを確認したいと思います。
しかし、Webサービスアプリケーションをテストするには、Tomcat 7サーバーにデプロイする必要があります。

Mavenを構成してwarを構築し、それをTomcatにデプロイして(理想的には、このために別のTomcatインスタンスを実行する)、JUnitテストを実行する方法がわかりません。
どんな助けにも感謝します。

私はMaven 2.2.1を使用しています

36
Michał Herman

Mavenでこのタイプの統合テストを処理する方法については、多くの考え方があります。

アプリケーションサーバーにアプリケーションをデプロイするときは、ユニットテストの領域にはもういません。アプリケーション全体がコンテナ内にデプロイされているため、これら2つのコンポーネントの統合をテストしています。

統合テストを実行するためにJUnitを使用しても何も問題はありません(ただし、たとえばユニットテストは、個々のテストのシーケンスについて気にする必要はありませんが、いくつかの制限があります) -正しく記述していると仮定-JUnit enforcesこれは、実行の順序を保証しないためです... Java 1.7より前のバージョンでは、テストの順序によって実行順序が誤って暗示されていました。クラス内のメソッドですが、JUnitコントラクトの一部ではありません... 統合テスト、たとえばTestNGなど、他のテストフレームワークに切り替えて単体テストフォーカスを見つけた場合のJUnitがテスト開発の邪魔になっています)

覚えておくべき重要な点は、Mavenライフサイクルがnitテストの実行にtestフェーズを使用することです。

integrationテストに関しては、Mavenでテストを処理するための正しい方法について、2つ(および半分)の考え方があります。

学校1-フェイルセーフとintegration-test/verify

この考え方では、packageの後のフェーズを使用してコンテナを起動し、統合テストを実行し、コンテナを破棄し、最後にテスト結果を確認し、テストが失敗した場合はビルドを失敗させます。

NEVER EVER RUN mvn integration-test]とすると、コンテナが正しく破棄されないため、mvn integration-testと入力したいと思うときはいつでも、実際にmvn verifyと入力したいと思います(ああ、そうです。短くてタイプも簡単...ボーナス)

したがって、これを使用して次のことを行います。

  • forkpre-integration-testTomcat7:run=trueフェーズにバインドします
  • バインド failsafe:integration-testintegration-testフェーズにバインド
  • バインド Tomcat7:shutdownpost-integration-testフェーズにバインド
  • Failsafe:verifyをverifyフェーズにバインドします。

追加のブラウニーポイントについては、 build-helper-maven-plugin:reserve-network-portvalidateフェーズにバインドして、テストサーバーが未使用のネットワークポートで確実に起動されるようにします。次に、テストリソースに対してリソースフィルタリングを使用して、ポートをテストに渡すか、または systemPropertyVariables を介して渡されるシステムプロパティを使用して、ポート番号をテストで使用できるようにします。

メリット

  • クリーンなMavenビルド
  • テストが失敗すると、プロジェクトをリリースできません
  • テストが遅すぎてすべてのビルドを実行できない場合は、統合テストを別のプロファイルに移動できます(慣例により、run-itsと呼ばれます)。

短所

  • IDEからテストを実行するのは難しい。すべての統合テストはITで開始/終了し、MavenはSurefireでTestで開始/終了するテストを実行し、FailsafeでITで開始/終了するテストを実行することを知っています。 IDEはおそらくそうではありません。さらに、IDEがコンテナを起動することはないため、実際にテストを手動で実行するには、手作業で多くの作業を行う必要があります。
  • テストをデバッグするには、2つのデバッガー(例: 1つはコンテナで実行されているアプリケーションをデバッグするためのもので、もう1つは テストケースをデバッグする のためのものです。

    mvnDebug -Dmaven.failsafe.debug=true verify
    
  • テストをMavenビルドプロセスに結合します。

学校2-別のモジュール

この考え方では、統合テストをwarモジュールに依存する別のモジュールに移動し、warをテストリソースにコピーします。 dependency:copy-dependencies テストするTomcat7依存関係と結合されたgenerate-test-resourcesフェーズにバインドされます。

テストケース自体が 組み込みモード を使用してTomcat7コンテナを起動します

メリット

  • テストはIDEで実行できます
  • 統合テストはユニットテストから分離されているため、IDEにすべてのテストを実行するように依頼しても、遅いテストは開始されません。

短所

  • warアーティファクトは、packageフェーズを通過した場合にのみ再構築されるため、IDEを使用する場合、テスト対象のコードを更新するために少なくともmvn clean packageを定期的に実行する必要があります。
  • 統合テストの失敗はwarモジュールのビルドを中断しません。そのため、壊れたwarアーティファクトをリリースして、統合テストモジュールのreactorビルドを失敗させることができます。一部の人々は、src/it内に統合テストモジュールを配置し、Maven Invokerプラグインを使用してテストを実行することでこの問題に対処しています...しかし、これはIDE統合をより貧弱にするため、その行はお勧めしません。
  • Mavenから統合テストカバレッジレポートを取得するのは困難です。
  • コンテナーをコーディングして、テストケース内から自分で開始/停止する必要があります。

School 2.5-独自のTomcat7サーバーを起動するテストケースによるフェイルセーフ

これは、2つのアプローチの一種のハイブリッドです。

Failsafeを使用してテストを実行しますが、テスト自体は、テストするTomcat7コンテナーの開始と停止を担当します。

メリット

  • Maven pomでサーバーの起動/停止を構成する必要はありません
  • IDEはすべてのテストを安全に実行できます(ただし、統合テストは遅くなる可能性があり、実行しないこともできますが、テストが失敗しない限り、すべてが失敗するわけではありません)。
  • IDEからテストをデバッグするのがより簡単になりました(アタッチするプロセスは1つだけです。通常、IDEを使用すると、特別なテストランナーを提供することでテストを簡単にデバッグできます)。

短所

  • コンテナーをコーディングして、テストケース内から自分で開始/停止する必要があります

上記があなたがあなたが持っているオプションを理解するのに役立つことを願っています。他の微調整があるかもしれませんが、一般的に上記は現在Mavenとの統合テストのベストプラクティスと考えられています。

118

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

Stephen Connollyが説明するように、これを直接構成する方法はありません。フェイルセーフプラグインを使用してこれを解決する方法を説明します。 Mavenライフサイクルでは、テストのタイプをテストできます。そのうちの1つともう1つを統合テストする単体テストです。単体テストは、Mavenライフサイクルのテスト段階で実行できます。統合テストを行う場合は、検証段階で行うことができます。単体テストと統合テストの違いを知りたい場合、これは 良いもの です。デフォルトでは、ユニットテストクラスは***/*Test.Javaであり、**/*TestCase.Javaこの形式である必要があります。フェイルセーフプラグインは、**/IT*.Java**/*IT.Javaを検索します**/*ITCase.Java

例を示します。 enter image description here

ここに、1つの単体テストクラスと1つの統合テストクラスがあります。ここで、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ファイル)をデプロイする前に実行されます。ただし、統合テストは検証段階で実行されます。この段階であなたの要求が満たされれば幸いです。

0
GPrathap