従来のassertXXX()-Methodsの代わりにHamcrest-MatcherとassertThat()を使用する理由


153

AssertクラスのJavaDocの例を見ると

assertThat("Help! Integers don't work", 0, is(1)); // fails:
// failure message:
// Help! Integers don't work
// expected: is <1> 
// got value: <0>
assertThat("Zero is one", 0, is(not(1))) // passes

私は、大きなアドバンテージはないと思いassertEquals( 0, 1 )ます。

構成がさらに複雑になった場合のメッセージに適していますが、より多くの利点がわかりますか?読みやすさ?

回答:


172

assertFoo意図と完全に一致するものが存在する場合、大きな利点はありません。これらの場合、それらはほとんど同じように動作します。

しかし、やや複雑なチェックを行うと、利点がより明確になります。

assertTrue(foo.contains("someValue") && foo.contains("anotherValue"));

assertThat(foo, hasItems("someValue", "anotherValue"));

どちらが読みやすいかを検討することができますが、アサートが失敗すると、からは適切なエラーメッセージが表示されますがassertThat、からの情報はごくわずかassertTrueです。

assertThatアサーションが何であったか、代わりに何が得られたかがわかります。あなたが期待した場所をassertTrue得たと言うだけfalseですtrue


私もこの質問を頭の中に入れていました。ありがとう、こんなふうに思ったことはない。
ウィーティー2009年

1
また、テストごとに1つのアサーションの「ルール」に役立ち、BDDスタイルの仕様とより簡単に融合します。
ニルスWloka

2
また、アサーションメカニズムを条件から分離します(これにより、エラーメッセージが改善されます)。
SteveD 2010

2
シングルでassertTrueを使用することはほとんどないので、この例は信じられません&&。それを2つの条件に分けると、JUnitでも問題の原因が明らかになります。誤解しないでください。私はあなたに同意します、私はあなたの例が嫌いです。
maaartinus 2017

48

バージョン4.4(導入された場所)のJUnit リリースノートには、4つの利点が記載されています。

  • より読みやすく入力可能:この構文を使用すると、動詞、オブジェクト、件名(assert "equals 3 x")を使用するassertEqualsではなく、件名、動詞、オブジェクト(assert "x is 3")の観点から考えることができます。
  • 組み合わせ:任意のマッチャーステートメントsは、否定(not(s))、組み合わせ(both(s).or(t))、コレクションにマッピング(each(s))、またはカスタムの組み合わせで使用できます(afterFiveSeconds(s)
  • 読み取り可能な障害メッセージ。(...)
  • カスタムマッチャー。自分でMatcherインターフェースを実装することにより、独自のカスタムアサーションに対して上記のすべての利点を得ることができます。

新しい構文を作成した人からのより詳細な議論:ここ


39

基本的にコードの可読性高めるため

hamcrestのほかに、festアサーションを使用することもできます。それらはhamcrestに比べていくつかの利点があります

いくつかの例

import static org.fest.assertions.api.Assertions.*;

// common assertions
assertThat(yoda).isInstanceOf(Jedi.class);
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);
assertThat(frodo).isIn(fellowshipOfTheRing);
assertThat(sauron).isNotIn(fellowshipOfTheRing);

// String specific assertions
assertThat(frodo.getName()).startsWith("Fro").endsWith("do")
                           .isEqualToIgnoringCase("frodo");

// collection specific assertions
assertThat(fellowshipOfTheRing).hasSize(9)
                               .contains(frodo, sam)
                               .excludes(sauron);


// map specific assertions (One ring and elves ring bearers initialized before)
assertThat(ringBearers).hasSize(4)
                       .includes(entry(Ring.oneRing, frodo), entry(Ring.nenya, galadriel))
                       .excludes(entry(Ring.oneRing, aragorn));

2016年10月17日更新

Festはアクティブではなくなりました。代わりにAssertJを使用してください


4
フェストは死んだようですが、フォークAssertJは非常に生きています。
Amedee Van Gasse、2016

18

非常に基本的な理由は、新しい構文を台無しにするのは難しいということです。

テスト後、特定の値fooが1であると仮定します。

assertEqual(1, foo);

-または-

assertThat(foo, is(1));

最初のアプローチでは、正しい順序を忘れて逆に入力するのは非常に簡単です。次に、1を期待して2を得たためにテストが失敗したと言うのではなく、メッセージは逆です。テストに合格した場合は問題ありませんが、テストが失敗した場合は混乱が生じる可能性があります。

2番目のバージョンでは、この間違いを犯すことはほとんど不可能です。


...そしてEclipseがアサーションの失敗を報告するときに、従来のassertThat()で引数を間違った方法で配置した場合、エラーは意味がありません。
Sridhar Sarnobat

9

例:

assertThat(5 , allOf(greaterThan(1),lessThan(3)));
//  java.lang.AssertionError:
//  Expected: (a value greater than <1> and a value less than <3>)
//       got: <5>
assertTrue("Number not between 1 and 3!", 1 < 5 && 5 < 3);
//  java.lang.AssertionError: Number not between 1 and 3!
  1. テストをより具体的にすることができます
  2. テストが失敗した場合、より詳細な例外が発生します
  3. テストを読みやすくする

ところで:assertXXXにもテキストを書くことができます...


1
いっそのこと、私は中に文字列引数を省略するだろうassertThat「予想:(<1>より価値の大きい少ない<3>よりも値)」あなたは自動的に取得するメッセージがちょうど有益ようですので、ケース
MatrixFrog

はい、そうです。回答を編集します。もともと私は(Matcher)。と(Matcher)の両方を使用したいのですが、うまくいきませんでした。
MartinL

3
assertThat(frodo.getName()).isEqualTo("Frodo");

自然言語に近いです。

読みやすく、コードを簡単に分析できます。プログラマーは、新しいコードを書くよりもコードを分析するためにより多くの時間を費やします。したがって、コードの分析が容易になれば、開発者はより生産的になるはずです。

PSコードはよく書かれた本でなければなりません。自己文書化されたコード。


4
OK、そして…?それが良いことである理由を説明することで、あなたの主張を支持することをお勧めします。
Nathan Tuggy、2015

0

assertEqualsに比べてassertThatには利点があります
-1)可読性が高い
2)失敗に関する詳細情報
3)実行時エラーではなくコンパイル時エラー
4)テスト条件
を記述する柔軟性5)移植性-hamcrestを使用している場合-jUnitを使用できますまたは基盤となるフレームワークとしてのTestNG。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.