プログラミングメモ

ソフトウェア開発に関する技術メモ。

Mavenで一部のテストの実行/除外を切り替える

やりたいこと

  • 一部のテストは、普段(mvn test で実行したとき)は実行されないようにする。
  • ただし、mvn の引数で何かを指定すれば実行できるようにする。
  • また、そのテストは、NetBeansから「ファイルのテスト」で単独実行されるようにする。

使用した環境

JUnitの@Categoryを使ってテストをグループ分け

「一部のテスト」には、JUnitの@Categoryでカテゴリを指定することで、他のテストと区別する。
Maven側では、特定のカテゴリのみテストを実行したり、テスト対象から除外したりできる。

カテゴリを指定するためには、カテゴリを表すマーカー用のクラスかインタフェースを作り、それをテストクラスに@Categoryを使って指定する。

マーカー用のインタフェースの例。インタフェース名は何でもよい。 (src/test/java 配下に置く)

package sample.maven.test;

public interface ExtraTest {
}

@Categoryを指定したテストクラスの例

package sample.maven;

import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.experimental.categories.Category;
import sample.maven.test.ExtraTest;

@Category(ExtraTest.class)
public class GreeterSlowTest {
    @Test
    public void testSlowSayHello() {
        String actual = new Greeter().sayHello("Suzuki");
        String expected = "Hello Suzuki!";
        assertEquals(expected, actual);
    }
}

普段のテストから指定のカテゴリを除外する

maven-surefire-plugin プラグインを設定して、指定のカテゴリをテスト対象から除外する。
pom.xmlmaven-surefire-pluginの設定がなければ、暗黙の設定がどうなっているかを、mvn help:effective-pom で確認できる。mvn help:effective-pom を実行すると、pom.xmlで記述していないものも含め、現在有効になっている設定が表示される。試した環境では、maven-surefire-plugin の暗黙の設定は次のようになっていた。

 <plugin>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.10</version>
   <executions>
     <execution>
       <id>default-test</id>
       <phase>test</phase>
       <goals>
         <goal>test</goal>
       </goals>
     </execution>
   </executions>
 </plugin>

これを自分の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>sample</groupId>
    <artifactId>MavenSample</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>MavenSample</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version> <!-- 4.8以上が必要 -->
            <scope>test</scope>
        </dependency>
    </dependencies>
  
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>  <!-- 2.13以上? が必要  -->
                <executions>
                    <execution>
                        <id>default-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <excludedGroups>sample.maven.test.ExtraTest</excludedGroups>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

ポイントは、

  • surefireの設定にexcludedGroupsを追加して、除外したいカテゴリのマーカー用クラス/インタフェースを指定。

また、

  • surefireプラグインのバージョンは、おそらく、2.13以上 (それより古いバージョンの場合、JUnit47 providerの設定が必要らしい。)
  • JUnitのバージョンは4.8以上

以上の設定で、 mvn test を実行したときには @Category(ExtraTest.class)の付いたテストは対象から除外される。

指定のテストだけ実行するための設定

surefireプラグインは、パラメータgroupsにカテゴリのマーカー用クラス/インタフェースを指定すると、そのカテゴリだけを対象にテストを実行する。これを利用すれば所望の設定ができる。

一方、surefireプラグインは、上記の設定により、ExtraTestは除外するよう設定済みである。しかし、
executionタグを追加し既存とは異なるidを指定することにより、別の設定のsurefireプラグインを追加することが可能となる。

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <executions>
                    <execution>
                        <id>default-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <excludedGroups>sample.maven.test.ExtraTest</excludedGroups>
                        </configuration>
                    </execution>
                    <!-- ここから追加 -->
                    <execution>
                        <id>extra-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <groups>sample.maven.test.ExtraTest</groups>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

ここでは、extra-testというidでsurefireの設定を追加した。

なお、以下の指定は

    <phase>test</phase>
    <goals>
        <goal>test</goal>
    </goals>

次のような意味になる。

surefireプラグインが提供しているゴールは"test" 1個だけであり、そのゴールはJUnitなどを使ってテストを実行する。つまり、mvn test と実行すれば、extra-testと名づけた設定でsurefireプラグインによるテストが実行される。

この設定のままだと mvn test したときには、デフォルト(id: default-test)と、追加した id: extra-test の両方が実行されてしまう。extra-testのほうは普段は実行せず、明示的に指定されたときだけ実行されるようにしたい。これは、surefireプラグインのパラメータ skipTests と、mavenのプロパティを利用して実現できる。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <skipExtraTest>true</skipExtraTest> <!-- これを追加 -->
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <executions>
                    <execution>
                        <id>default-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <excludedGroups>sample.maven.test.ExtraTest</excludedGroups>
                        </configuration>
                    </execution>
                    <execution>
                        <id>extra-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <skipTests>${skipExtraTest}</skipTests> <!-- これを追加 -->
                            <groups>sample.maven.test.ExtraTest</groups>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

surefireプラグインのskipTestsパラメータにtrueを指定すると実行はスキップされる。 skipTestsの値は、独自に追加したskipExtraTestプロパティで与えるようにして、skipExtraTestプロパティのデフォルト値はtrueにしておく(propertiesタグに追加した設定により指定している)。すなわち、デフォルトではスキップされる。

extra-testを実行したい場合は、次のようにskipExtraTestをfalseにして実行すればよい。

mvn -DskipExtraTest=false test

NetBeansからの実行

テストプログラム作成中は「ファイルをテスト」「ファイルのテストをデバッグ」を使って、作成中のテストクラスだけ実行させるのが便利だが、この場合は、@Categoryの有無にかかわらず指定のテストクラスが実行される。

どうやらこのケースの場合は、ここまでで定義したid: default-test, id: extra-testのどちらの設定も適用されていないようだ。「ファイルをテスト」の場合、NetBeansは、mvn test ではなく mvn surefire:test のように、直接ゴール(surefire:test)を指定して実行している。そしてこの場合適用される設定は id: default-test ではなくid: default-cli となるようだ。このことは、mvn surefire:test を実行したときの次の表示から推測できる。

--- maven-surefire-plugin:2.16:test (default-cli) @ MavenSample ---

なお、実行>プロジェクトをテスト の場合は、mvn test で実行されるため、id: extra-testはスキップされる。

備考

プラグインの設定記述例としてよく見かけるのは、次のようにexecutionsタグを使わずにconfigurationを書いている例だが、この場合は、暗黙に定義されているものも含め、すべてのidの設定にこの設定が追加されるようだ。

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <configuration>
                    <excludedGroups>sample.maven.test.ExtraTest</excludedGroups>
                </configuration>
            </plugin>

このため、上記の設定であれば、NetBeansから「ファイルをテスト」を実行した場合にもExtraTestは除外される。つまり、ExtraTestをつけたテストクラスは「ファイルをテスト」では実行できなくなってしまう。