「assertThat」と検索すると私のブログに引っかかる人がいるようなので、この記事を書きました。ただ「AssertJ」と検索すると、たくさん有用な記事も見つかります。
なので、この記事は「AssertJ徹底解説」ではなく、「きり丸がよく使うAssertJのメソッド」というところで新規性を出していきます。
環境
※ 上記を指定せず、下記で一気にimportしています。
org.springframework.boot:spring-boot-starter-test:2.2.4.RELEASE
を使用しています。
まとめ
- 必須級
- isEqualTo
- isInstanceOfSatisfying
- 準必須級
- SoftAssertions
- あったら便利
- hasSize
だけ覚えれば問題ありません。
必須級
isEqualTo
比較対象が同一であることを確認します。基本中の基本です。ただし、isEqualTo
で使うために不必要に情報を丸めてしまい、エラーメッセージが適切でないことがあるので注意。ちゃんとエラーメッセージのレポートを確認しながら、テストしましょう。
String actual = "123"; String expect = "123"; assertThat(actual).isEqualTo(expect);
なお、Javaの仕様上、クラスでequals
メソッドが実装されていないと、インスタンスが違う場合は比較できません。めんどくさいので、わたしはLombokで@Data
や@Value
で自動生成させてます。
@Test void test_001(){ Animals expect = new Animals("100"); Animals actual = new Animals("100"); assertThat(actual).isEqualTo(expect); }
NGなパターン。
class Animals{ String id; Animals(String id){ this.id = id; } }
エラーメッセージ。
Expecting: <jp.co.kelly.biz.domain.NestedList$Animals@268d9b4b> to be equal to: <jp.co.kelly.biz.domain.NestedList$Animals@3098daa7>
OKなパターン。
class Animals{ String id; Animals(String id){ this.id = id; } @Override public boolean equals(Object obj){ Animals animals = (Animals)obj; return this.id.equals(animals.id); } }
同じインスタンスであることを確認したい場合は、isSameAs
がありますが…。私は中身が同じであれば、インスタンスが別でもいいので、isSameAs
は使わないです。
isInstanceOfSatisfying
エラーのハンドリングが正しいことを確認する。assertThatThrownByと組み合わせる。
// Bookクラス public class Book{ String isbn; public Book(String isbn){ if (isbn.length() == 13){ throw new RuntimeException("ISBNの桁数が正しくない"); } } }
エラーが発生しうる条件でassertThatThrownBy
メソッドを呼びます。isInstanceOfSatisfying
には第一引数に目的のExceptionのクラス、第二引数にExceptionの中身を確認します。もし、Exceptionが発生することだけを確認したければ、isInstanceOf
でも問題ありません。
assertThatThrownBy( () -> new Book("1") ).isInstanceOfSatisfying( RuntimeException.class, (e) -> assertThat(e.getMessage()).isEqualTo("ISBNの桁数が正しくない") ); // Exceptionの中身は無視したい場合 assertThatThrownBy( () -> new Book("1") ).isInstanceOf( RuntimeException.class );
同等のメソッドをassertThatThrownByとisInstanceOfSatisfyingを使わなかった時の書き方も記載しておきます。正常終了しない場合と目的以外のExceptionが発生した場合を確認しなければならないので、書き方が非常に大変です。
try{ new Book("1"); fail(); } catch (RuntimeException e){ assertThat(e.getMessage()).isEqualTo("ISBNの桁数が正しくない") } catch(Exception e){ fail(); }
準必須級
SoftAssertions
複数のテストを一気にテストができるようになります。例えば、下記の例でhasSize
で100と指定すると通常であれば後続のテストが動きません。SoftAssertionsを使用すれば、途中で失敗しても全てテストしてくれます。ただし、これはテストを後回しにする方法なので、assertAll
を呼び忘れるとテストされずに正常終了します。
List actual = List.of("1", "2"); List expect = List.of("1", "2"); SoftAssertions softly = new SoftAssertions(); softly.assertThat(actual).hasSize(2); softly.assertThat(actual).isEqualTo(expect); softly.assertThat(actual).contains("1", "2"); // ここで一気に比較する。忘れてはいけない! softly.assertAll();
これはチェイン的な書き方しても、メリットがあります。通常通りであれば、下記のエラーメッセージしか出てきません。
assertThat(actual) .hasSize(100) .isEqualTo(null) .contains("1","2","3");
エラーメッセージ。
Expected size:<100> but was:<2> in: <["1", "2"]> at jp.co.kelly.biz.domain.AssertX.test_xxx(AssertX.java:95)
しかし、SoftAssertionsを組み合わせることで、一度のテストで下記のメッセージが出力されます。特にエラーの行数も一緒に出力されるので、かなり好きです。
softly.assertThat(actual) .hasSize(100) .isEqualTo(null) .contains("1","2","3"); softly.assertAll();
Expected size:<100> but was:<2> in: <["1", "2"]> at AssertX.test_xxx(AssertX.java:95) Expecting: <["1", "2"]> to be equal to: <null> but was not. at AssertX.test_xxx(AssertX.java:96) Expecting: <["1", "2"]> to contain: <["1", "2", "3"]> but could not find: <["3"]> at AssertX.test_xxx(AssertX.java:97)
なお、私はチェイン的な書き方よりも、1行1行確認する方が好きです。
書き方としては優れていますが、テスト成功している行に対して処理を追加する必要があります。そのことにより、既存のテストを壊してしまう可能性があることに違和感があります。
この辺に関しては好みですが、テストはできる限りシンプルにしたいので1行1行確認する方が好きです。
他の言語でも同様の挙動するメソッドがあるはずなので調べてみてください。Pythonではsubtestというメソッドが同等の動きをする認識です。
あったら便利
hasSize
Listのサイズを確認できます。最終的にはhasSize
の確認は不要になりますが、TDDで小さく確認するときの足掛かりになるので、私はまずサイズ確認してからそのあとリストのisEqualTo
を使用しています。
List actual = List.of(1, 2, 3); List actual = List.of(1, 2, 3); assertThat(actual).hasSize(3); assertThat(actual).isEqualTo(expect);
Collection型のsize()
を使ってisEqualTo
を使う方法もありますが、中身の検証をしたいのか、サイズの検証をしたいのか一見で分からなくなります。なので、sizeに関してはhasSize
を使用しています。
assertThat(actual.size()).isEqualTo(3); // サイズを知りたい? assertThat(actual.get(2)).isEqualTo(3); // 中身を知りたい?
まとめ
- 必須級
- isEqualTo
- isInstanceOfSatisfying
- 準必須級
- SoftAssertions
- あったら便利
- hasSize
終わりに
テストはできる限りシンプルにしたいので、使用するメソッドをできる限り減らしたいと考えてます。シンプルな方が、もしJUnit6が出て、AssertJが対応しなかった時に移行もしやすいですからね。もちろん、エラーメッセージが適切になるので、メソッドを覚えれば覚えるほどわかりやすいです。
もっといろいろと知りたい場合は、下記にAssertJのサンプルページもあるので、そちらから色々見てください。
参考記事
AssertJの公式ページ
AssertJのサンプルページ
AssertJ使い方メモ(Qiita)
assertEqualsとassertThatの比較記事
もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、Twitterのフォローもよろしくお願いします。私の励みになります。