🔖

Maven/GradleでJUnitテストのもろもろ

2022/02/08に公開

テストに失敗した際にスタックトレースを出力させる

Maven/GradleでJUnitテストに失敗した際に出力されるログには、デフォルトではテスト側コードの失敗した1行しか出力されないようになっています。
そのためテスト対象コードのどこで失敗したのかわからないことがあります。

public class PersonService {
  public String getName() {
    throw new RuntimeException();
  }
}

class PersonServiceTest {
  @Test
  void 名前を取得() {
    String actual = new PersonService().getName();
    assertEquals("hanako", actual);
  }
}
$ mvn test
[ERROR] 名前を取得  Time elapsed: 0.035 s  <<< ERROR!
java.lang.RuntimeException
	at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)

$ ./gradlew test
PersonServiceTest > 名前を取得() FAILED
    java.lang.RuntimeException at PersonServiceTest.java:10

この場合だとPersonServiceTestが失敗したことはわかりますが、PersonServiceのどの場所で失敗したのかわかりません。今回のものはシンプルなコードなので困ることも少ないと思いますが、テストクラス対象から別のクラスを呼び出して・・・となると原因を調査するのが大変になります。
そこでスタックトレースを出力できるように設定します。

Maven

-DtrimStackTrace=false をつけてtest実行するかmaven-surefire-pluginのconfigurationにtrimStackTrace=falseを設定することでスタックトレースを全て出力することが可能です。

-DtrimStackTrace=falseの場合

$ mvn -DtrimStackTrace=false test
[ERROR] 名前を取得  Time elapsed: 0.027 s  <<< ERROR!
java.lang.RuntimeException
	at com.example.testdemo.PersonService.getName(PersonService.java:8)
	at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)
--- 省略 ---

maven-surefire-pluginのconfigurationにtrimStackTrace=falseを設定する場合

pom.xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <trimStackTrace>false</trimStackTrace>
    </configuration>
</plugin>
$ mvn test
[ERROR] 名前を取得  Time elapsed: 0.026 s  <<< ERROR!
java.lang.RuntimeException
	at com.example.testdemo.PersonService.getName(PersonService.java:8)
	at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)
--- 省略 ---

Gradle

testタスクのtestLoggingプロパティのexceptionFormatプロパティにfullを設定します。

build.gradle
test {
    testLogging {
        exceptionFormat "full"
    }
}
$ ./gradlew test
PersonServiceTest > 名前を取得() FAILED
    java.lang.RuntimeException
        at com.example.testdemo.PersonService.getName(PersonService.java:8)
        at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)

テストの失敗を無視する

テストに失敗してもビルドなどをしたい場合の方法です。
具体的な利用イメージとしてはテストコードがメンテされずに、CIを導入時に大量のエラーが出て困るみたいなケースが想定されます。

Maven

-Dmaven.test.failure.ignore=trueをつけてtest実行をするか、maven-surefire-pluginのconfigurationにtestFailureIgnore=trueを設定ことでスタックトレースを全て出力することが可能です。

-Dmaven.test.failure.ignore=trueの場合

$ mvn -Dmaven.test.failure.ignore=true test
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.028 s <<< FAILURE! - in com.example.testdemo.PersonServiceTest
[ERROR] 名前を取得  Time elapsed: 0.022 s  <<< ERROR!
java.lang.RuntimeException
	at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

をつけてtest実行をするか、maven-surefire-pluginのconfigurationにtestFailureIgnore=trueを設定する場合

pom.xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <testFailureIgnore>true</testFailureIgnore>
    </configuration>
</plugin>
$ mvn test
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.03 s <<< FAILURE! - in com.example.testdemo.PersonServiceTest
[ERROR] 名前を取得  Time elapsed: 0.023 s  <<< ERROR!
java.lang.RuntimeException
	at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Gradle

testタスクのignoreFailuresプロパティにtrueを設定します。

build.gradle
test {
    testLogging {
        ignoreFailures true
    }
}
$ ./gradlew test
PersonServiceTest > 名前を取得() FAILED
    java.lang.RuntimeException
        at com.example.testdemo.PersonService.getName(PersonService.java:8)
        at com.example.testdemo.PersonServiceTest.名前を取得(PersonServiceTest.java:10)

2 tests completed, 1 failed

BUILD SUCCESSFUL in 7s

参考

Maven -> surefire:test
Gradle -> Test
Gradle -> TestLoggingContainer

Discussion