我为什么要使用Hamcrest-Matcher和assertThat()而不是传统的assertXXX() - 方法

时间:2009-11-09 13:56:37

标签: java testing junit junit4 hamcrest

当我查看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 )

如果构造变得更复杂但是你看到更多的优势,那么对于消息可能很好吗?可读性?

7 个答案:

答案 0 :(得分:167)

对于存在与您的意图完全匹配的assertFoo的情况,没有什么大的优势。在这些情况下,他们的行为几乎相同。

但是当你进行更复杂的检查时,优势就变得更加明显了:

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

VS

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

可以讨论哪一个更易于阅读,但一旦断言失败,您将从assertThat收到一条好的错误消息,但只有来自assertTrue的极少量信息

assertThat会告诉你断言是什么以及你得到了什么。 assertTrue只会告诉您false您预期true的位置。

答案 1 :(得分:45)

版本4.4的JUnit release notes(引入它的地方)说明了四个优点:

  
      
  • 更具可读性和可输入性:此语法允许您根据主语,动词,对象(断言“x为3”)而不是 assertEquals 进行思考,它使用动词,对象,主语(断言) “等于3 x”)
  •   
  • 组合:任何匹配器语句都可以被否定( not(s)),组合((s)。或(t)),映射到集合( each(s)),或在自定义组合中使用( afterFiveSeconds(s)
  •   
  • 可读失败消息。 (...)
  •   
  • 自定义匹配器。通过自己实现 Matcher 接口,您可以获得自己的自定义断言的所有上述好处。
  •   

来自创建新语法的人的更详细论证:here

答案 2 :(得分:38)

基本上提高代码的可读性

除了hamcrest,您还可以使用fest assertions。 他们比hamcrest 具有一些优势,例如:

  • 他们更具可读性 (assertEquals(123, actual); // reads "assert equals 123 is actual" vs assertThat(actual).isEqualTo(123); // reads "assert that actual is equal to 123")
  • 它们是可被发现的(you can make autocompletion work with any IDE)。

一些例子

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

答案 3 :(得分:18)

一个非常基本的理由是很难搞乱新语法。

假设测试后特定值foo应为1。

assertEqual(1, foo);

- 或 -

assertThat(foo, is(1));

使用第一种方法,很容易忘记正确的顺序,并向后键入它。然后,而不是说测试失败,因为它预期1并得到2,消息是倒退的。测试通过时不成问题,但在测试失败时会导致混淆。

对于第二个版本,几乎不可能犯这个错误。

答案 4 :(得分: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. 更容易阅读测试
  4. btw:你也可以在assertXXX中写文字......

答案 5 :(得分:3)

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

接近自然语言。

易于阅读,更轻松地分析代码。 Programer花费更多时间来分析代码而不是编写新代码。因此,如果代码易于分析,那么开发人员应该更有效率。

P.S。 代码应该写得很好。 自我记录的代码。

答案 6 :(得分:1)

断言断言等于断言是有好处的 -
 1)更具可读性  2)有关失败的更多信息
 3)编译时错误 - 而不是运行时错误
 4)写作测试条件的灵活性
 5)可移植 - 如果您使用hamcrest - 您可以使用jUnit或TestNG作为底层框架。