SpringBootで作成したWebアプリのIntegration Test目的でSelenium WebDriverを組み込んだJUnitをMavenから実行したとき、初期データ構築のために発行されたINSERT文のSQLが、SQLファイルをUTF-8で保存しているにもかかわらずMS932として解釈されて実行されていた。
※ちなみにこのSQLファイルは、SpringBootが起動時に実行してくれるdata.sql。
このせいでWeb画面の検索フォームで日本語を入力してDBを検索するというテストでは、アプリケーションに渡る文字は正しい日本語なのに対してDBに保存されている日本語が文字化けしているため、必ず失敗するようになってしまった。
このテストはEclipseの「実行」→「JUnitテスト」から起動するときは問題なく成功する。
環境は以下の通り。
Windows 7, Java 8, JUnit 4, Maven 3.3.3, SpringBoot 1.3.3
問題の根本原因は、Windows 7でJavaを実行したときのデフォルトのfile.encodingはMS932なので、UTF-8の日本語がうまく解釈できていないことにある。
System.out.println(System.getProperty("file.encoding"));
// MS932
WindowsでMavenを動かすときの文字エンコード絡みの注意点としては、Web上に情報が出回っている通り、pom.xmlでpropertiesのproject.build.sourceEncodingに設定をしてあげれば良い。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
しかし今回の問題はproject.build.sourceEncodingを設定しても解決しない。
JUnitがMavenの実行プロセスとは別で起動されるということが原因で起こるからだ。
project.build.sourceEncodingとは別に、maven-surefire-pluginで文字エンコードの設定をする必要がある。maven-surefire-pluginはUnit Testにおいて使われるプラグインで、 ${basedir}/target/surefire-reports
にレポートを出力するのが主な役割になる。
今回の設定で見るべきは、JVM引数を渡している <argLine>-Dfile.encoding=UTF-8</argLine>
になる。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<junitArtifactName>junit:junit</junitArtifactName>
<encoding>UTF-8</encoding>
<inputEncoding>UTF-8</inputEncoding>
<outputEncoding>UTF-8</outputEncoding>
<argLine>-Dfile.encoding=UTF-8</argLine>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
【余談】
この解決方法は、文字コード周りで困っていそうな日本人でも中国人でもなくイタリア人のサイト(https://carlobertoldi.wordpress.com/2012/03/12/maven-unit-tests-and-those-funny-characters/)で見つけた。