Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

RestfuseによるREST API自動試験まとめ(その2)

こんにちは、Web系エンジニアのナカガワです。
皆さん、エンジニアtypeに掲載された私の雄姿(><)は見て頂けましたか?

「技術探求型」で新しい受託開発を実現してきたアクロクエストが有する“組織技術力”とは? - エンジニアtype
まだの人はいますぐチェック!!

さて、前回はRestfuseを使ったテストの手順を説明しました。今回はそのテストをJenkinsで自動化するまでの手順を紹介したいと思います。

f:id:acro-engineer:20140122102519p:plain

Jenkinsを使ってどのような自動試験にするか

まずはEclipseプロジェクトやJenkinsプロジェクトをどのような構成にするかを考えます。
前回の手順では「アプリケーション本体(=テスト対象)」と「結合テスト」を別のEclipseプロジェクトにしました。そのため、Jenkinsプロジェクトでも同様に、この2つに分けて構築しました。
2つのプロジェクトに分けることで、アプリケーション本体側のテストコードと、結合テスト側のテストコードを分けることができます。たとえば実際の業務では、アプリケーション本体側をシンプルなユニットテストにして、結合テスト側をAPサーバやDBサーバを利用した結合テストにしていました。

つまり、Jenkinsで以下のように処理することになります。

  1. アプリケーション本体をビルドしてwarファイルを作成する
  2. warファイルを、テスト用プロジェクトにコピーする
  3. APサーバを起動する
  4. テストを実行する
  5. APサーバを停止する

それでは、実際に設定する手順を説明します。

Jenkinsの自動試験用の設定

1. プロジェクトの作成

まずはJenkinsを起動して、プロジェクト作成します。
※Jenkinsインストールは割愛しますね。

アプリケーション本体も、結合テスト用プロジェクトも、いずれもMavenプロジェクトなので、ビルドは「Maven2/3プロジェクトのビルド」を選択します。
※今回は業務の都合上、Mavenは3系ではなく2.2.1を使いました。

アプリケーション本体用と、結合テスト用プロジェクトのそれぞれについて、Jenkinsプロジェクトを作りました。

f:id:acro-engineer:20140115014614p:plain

どちらもMavenの実行において、clean installを指定しておきます。
結合テスト用のプロジェクトはinstallでなくてもintegration-testが実行されるものであれば構いません。

2. アプリケーション本体のビルドとwarファイルの保存

Jenkinsのパイプライン機能を使って「アプリケーションのビルド」→「テストプロジェクトの実行」の順に実行します。

ここでアプリケーションの「ビルド後の処理」に成果物の保存処理を追加しました。
アプリケーションのビルドの成果物であるwarファイルを保存しておくことで、他のプロジェクトにコピーすることができるようになります。
以下の通りですね。

f:id:acro-engineer:20140115014935p:plain

次は保存した成果物を結合テスト用プロジェクトにコピーします。

3. アプリケーション本体のwarファイルのコピー

結合テスト用プロジェクトに、先ほど作成・保存したwarファイルをコピーします。
今回はJenkinsプラグインの「Copy Artifact Plugin」を使います。当該プラグインは、Jenkinsの管理ページからインストールしました。

f:id:acro-engineer:20140115015134p:plain

上記プラグインを追加すると、Jenkinsプロジェクト内での「前処理」に「他のプロジェクトから成果物をコピー」が追加されます。
これを使えば、warファイルのコピーが可能になります。

ちなみに今回は、「ディレクトリ構造を無視」というチェックボックスにチェックを入れておきます。
このチェックを入れないと、コピー時にディレクトリ構成までコピーされてしまい、想定と違う場所にwarファイルが置かれてしまうからです。

これでworkを指定すればwork直下にwarファイルが配置されます。

f:id:acro-engineer:20140115015332p:plain

後はwarファイルを起動するだけですね。

4. アプリケーションの起動

warファイルを起動する方法はいくつかありますが、今回はMavenで簡単に起動できるjetty pluginを使います。
integration-testフェイズを利用し、pre-integration-testでJettyを起動し、post-integration-testでJettyを停止します。
※integration-testフェイズでテストを実施するのはsurfire-pluginを利用しました。

以下がテスト実行用のpom.xmlに追加した内容です。

      <!-- Jettyの設定 -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>8.1.14.v20131031</version>
        <configuration>
          <war>./work/restsample-1.0.0.war</war>
          <webApp>
            <contextPath>/restsample</contextPath>
          </webApp>
        </configuration>
        <executions>
          <!-- integration-test の 事前準備 (Jettyの起動) -->
          <execution>
            <id>start-jetty</id>
            <phase>pre-integration-test</phase>
            <goals>
              <goal>run-war</goal>
            </goals>
            <configuration>
              <scanIntervalSeconds>0</scanIntervalSeconds>
              <daemon>true</daemon>
            </configuration>
          </execution>
          <!-- integration-test の 事後処理 (Jettyの停止) -->
          <execution>
            <id>stop-jetty</id>
            <phase>post-integration-test</phase>
            <goals>
              <goal>stop</goal>
            </goals>
            <configuration>
              <stopKey>stop</stopKey>
              <stopPort>9999</stopPort>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- integration-testの実行 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <!-- integration-test にて実行する -->
        <executions>
          <execution>
            <id>selenium-test</id>
            <phase>integration-test</phase>
            <goals>
              <goal>test</goal>
            </goals>
            <configuration>
              <includes>
                <include>**/*Test*.java</include>
              </includes>
            </configuration>
          </execution>
        </executions>
      </plugin>

ところで、Jenkinsを8080番ポートで起動している場合は、Jettyを8080番ポートで起動すると、ポートが重複してしまってエラーになります。
というか、私自身、よくやってしまいます orz

JenkinsかJettyの利用するポートを変更する必要があります。
Jetty側のポートを変更するには、Jetty起動時のオプションに-Djetty.port=18080などをつけてください。その場合、結合テスト用のテストコードに記載しているURLも18080に変更する必要がある点に注意してください。

5. テストの実施

改めて実行してみたところ、Jenkinsのビルドには成功するものの、途中でテスト失敗のメッセージが出ていました。

結果ログをよく見ると、JUnitが3回起動していました。
どうやら上に書いた設定のままだと、Jetty起動前に2回JUnitが起動し、それがテスト失敗となっているようです。
Jetty起動前の試験は不要なので、スキップする設定を加えます。

      <!-- integration-testの実行 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <!-- integration-test にて実行する -->
        <executions>
          <execution>
            <id>selenium-test</id>
            <phase>integration-test</phase>
            <goals>
              <goal>test</goal>
            </goals>
            <configuration>
              <includes>
                <include>**/*Test*.java</include>
              </includes>
            </configuration>
          </execution>
          <!-- ★追加設定 default-test, unit-test をSKIPする -->
          <execution>
            <id>default-test</id>
            <configuration>
              <skip>true</skip>
            </configuration>
          </execution>
          <execution>
            <id>unit-test</id>
            <phase>test</phase>
            <goals>
              <goal>test</goal>
            </goals>
            <configuration>
              <skip>true</skip>
            </configuration>
          <!-- ★追加設定終わり -->
          </execution>
        </executions>
      </plugin>

上記設定でもう一度ビルドすると、無事、JUnitは1回しか実施されず、JUnitのテスト成功のみ残りました。

あとはJenkinsが毎日自動で統合テストを実施してくれるので、安心感があります。

まとめ

2回に分けて紹介してきましたが、最後に簡単にまとめです。

  1. Restfuseを使うと検証に集中してテストケースが書ける!
  2. アプリケーション本体と統合テスト用のJenkinsプロジェクトを分けたほうが管理しやすかった!
  3. みんな大好き、Jenkins + Jettyの組み合わせは、やっぱり鉄板だった!
  4. 8080番ポートを重複させるのは、素人(><)。
  5. Jenkinsで自動試験を常に動かすと安心感ある!

そんなわけで、REST APIの自動試験が必要な時には、Restfuse + Jenkinsも試してみてください!

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ