Чому я повинен використовувати Hamcrest-Matcher і assertThat () замість традиційного assertXXX () - Методи


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"));

vs.

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

Можна обговорити, який із них легше читати, але як тільки не буде твердження, ви отримаєте хороше повідомлення про помилку assertThat, але лише дуже мінімальну кількість інформації assertTrue.

assertThatрозповість, що було за твердження і що ви отримали замість цього. assertTrueскаже лише, що ти дістався falseтам, де очікував true.


У мене це питання теж було в глибині розуму. Дякую, я ніколи про це не думав.
пшениці

1
Це також допомагає з "правилом" одного твердження за тест і легше поєднується зі специфікаціями стилю BDD.
Нілс Влока

2
І це відокремлює механізм затвердження від умови (саме це призводить до кращих повідомлень про помилки).
SteveD

2
Приклад неправдоподібний, оскільки навряд чи хтось би використовував сингл assertTrueіз ан &&. Поділ її на дві умови робить проблему очевидною навіть у JUnit. Не розумій мене; Я згоден з вами, я просто не люблю ваш приклад.
maaartinus

48

Примітки до випуску JUnit для версії 4.4 (де вона була представлена) містять чотири переваги:

  • Більш читабельний і набраний: цей синтаксис дозволяє мислити в термінах суб'єкта, дієслова, об'єкта (стверджувати "x є 3"), а не assertEquals , який використовує дієслово, об'єкт, предмет (assrt "дорівнює 3 х")
  • Комбінації: будь-який випадок відповідника може бути заперечений ( not (s) ), об'єднаний ( або (або) .or (t) ), відображений у колекції ( кожен (и) ) або використаний у користувацьких комбінаціях ( afterFiveSeconds (s) )
  • Прочитані повідомлення про помилку. (...)
  • Спеціальні відповідники. Скориставшись інтерфейсом Matcher самостійно, ви можете отримати всі перераховані вище переваги для власних власних тверджень.

Більш детальна аргументація від хлопця, який створив новий синтаксис: тут .


39

В основному для підвищення читабельності коду .

Окрім сім'янки, ви також можете використати твердження фесту . Вони мають декілька переваг перед сімейством, зокрема:

Деякі приклади

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));

17 жовтня 2016 р. Оновлення

Fest більше не активний, замість цього скористайтеся AssertJ .


4
Здається, Фест помер, але вила AssertJ дуже жива.
Амедей Ван Гассе

18

Дуже основним виправданням є те, що важко зіпсувати новий синтаксис.

Припустимо, що певне значення, foo, має бути 1 після тесту.

assertEqual(1, foo);

--OR--

assertThat(foo, is(1));

При першому підході дуже легко забути правильний порядок і набрати його назад. Тоді замість того, щоб сказати, що тест не вдався, оскільки він очікував 1 та отримав 2, повідомлення повернеться назад. Не є проблемою, коли тест проходить, але може призвести до плутанини, коли тест не вдасться.

З другою версією зробити цю помилку майже неможливо.


... і коли Eclipse повідомляє про помилку твердження, якщо ви ставите аргументи неправильним способом у традиційному арсеналіThat (), помилка не має сенсу.
Шрідхар Сарнобат

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. простіше читати Тест

btw: Ви також можете написати текст у assertXXX ...


1
А ще краще, я б пропустив аргумент рядка у assertThatвипадку, тому що повідомлення, яке ви отримуєте автоматично, настільки ж інформативне: "Очікувано: (значення більше <1> і значення менше <3>)"
MatrixFrog

Так, ти маєш рацію. Я редагую свою відповідь. Спочатку я хочу використовувати обидва (Matcher) .and (Matcher), але це не вийшло.
MartinL

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

Близький до природної мови.

Легше читати, простіше аналізувати код. Програмер витрачає більше часу на аналіз коду, ніж на написання нового. Отже, якщо код буде легко проаналізувати, то розробник повинен бути більш продуктивним.

PS-код повинен бути як добре написаною книгою. Самодокументований код.


4
Гаразд, і…? Я рекомендую підтримати свій аргумент, пояснивши, чому це добре.
Натан Туггі

0

Є переваги стверджувати, що над assrtEquals -
1) більш читабельна
2) більше інформації про помилку
3) складати помилки часу - замість помилок часу виконання
4) гнучкість із написанням тестових умов
5) портативна - якщо ви використовуєте hamcrest - ви можете використовувати jUnit або TestNG як основу основи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.