パラメータ化テストを行うか否か迷った話
テスト対象メソッド
下記のようなメソッドの引数に入出力のファイルPATHを受け取り、ファイル出力するメソッドのテストを作成した時のお話。
割りと紆余曲折があったのでメモがてらまとめます。
コードは書きやすいのでGroovyで記述していますが、Groovy知らない方でも問題なく読めるかと思います。
テスト対象のメソッド
上記したようにファイルパスを受け取り、そのファイルの中身を読み取り、ゴニョゴニョした後指定PATHに出力するメソッド。
public class Hoge { void create(input, output) { def message = input.text // ファイルの中の文字列をゴニョゴニョして出力 output << message } }
パラメータ化テストを行わない場合のテストケース
テストケース
public class HogeTest { @Rule public TemporaryFolder temporaryFolderRule = new TemporaryFolder() @Rule public TestName testNameRule = new TestName() /** resourcesフォルダのPATH */ private static final resourcesPath = "test/resources" /** * 実行テストケースのメソッド名を元に入力値、期待値を作成しcreateメソッドをテストする */ private void executeCreateMethodTest() { // setUp def sut = new Hoge() def input = new File("${resourcesPath}/${testNameRule.methodName}_input.txt") def output = temporaryFolderRule.newFile(testNameRule.methodName) def expected = new File("${resourcesPath}/${testNameRule.methodName}_output.txt").text // Excercise sut.create(input, output) def actual = output.text // Verify assertThat(actual, is(expected)) } @Test public void ○○_正常系() { executeCreateMethodTest() } @Test public void ××_正常系() { executeCreateMethodTest() } }
test/resources ├○○_正常系_input.txt ├○○_正常系_output.txt ├××_正常系_input.txt └××_正常系_output.txt
メリット
- テストケースの一覧がアウトラインで一目瞭然
- テストケースを1件づつ実行可能
デメリット
- メソッド名のみ異なる全く同じメソッドが乱立する
- テストクラスが無駄に大きくなる
- 1つのテストケースのテスト内容がメソッドを見ないとわからない
- テストケースを追加しても件数が増えない(気分の問題)
疑問点
- そもそも共通メソッドにしない方が良い?
パラメータ化テストにした場合
テストケース
@RunWith(Theories.class) public class HogeTest { @Rule public TemporaryFolder temporaryFolderRule = new TemporaryFolder() @DataPoints public static String[] params = [ "○○_正常系", "××_正常系", ] /** resourcesフォルダのPATH */ private static final resourcesPath = "test/resources" @Theory public void 正常系の場合(String param) { // setUp def sut = new Hoge() def input = new File("${resourcesPath}/${param}_input.txt") def output = temporaryFolderRule.newFile(param) def expected = new File("${resourcesPath}/${param}_output.txt").text def msg = "[${param}]のテストに失敗。" // Excercise sut.create(input, output) def actual = output.text // Verify assertThat(msg, actual, is(expected)) } }
test/resources ├○○_正常系_input.txt ├○○_正常系_output.txt ├××_正常系_input.txt └××_正常系_output.txt
メリット
- テストコードを見るだけでテスト内容が一目瞭然
- テストケースの追加が簡単
デメリット
- テストケースを1件づつ実行不可能
- 1件失敗した場合にそれ以降のテストが実行されない
疑問点
- 失敗時のメッセージが微妙
まとめ
それぞれメリットデメリットがあり、パラメータ化テストを行うことがベストになるとは限らない。
今回のケースだと、パラメータ化テストを行わない方がベターな気がしました。
理由としては、今回のテスト対象のメソッドがファイルの入出力なので、テスト追加時に追加したテストケースだけを実行できなかったのは結構ストレス。
同様に、1件のテストケース追加にもそれなりに手間がかかるので追加したのにテストケース数が変わらないのもテスト作ってて楽しくないなと感じた事ですかね。(テストは楽しく作って楽しく実行するものって誰か偉い人が言ってた。)
そもそも、テスト対象がこのような場合はパラメータ化テストを行おうとするのが間違いだったりするのかな?とも思ったり。
また、本題とは関係ないけどRuleは簡単に使用できたのでこれからも積極的に使っていく予定。*4