Junit4: Представляет иерархию BiMatcher

Созданный на 8 февр. 2018  ·  9Комментарии  ·  Источник: junit-team/junit4

Хорошей функцией было бы введение иерархии BiMatcher (аналог org.hamcrest.Matcher , но с использованием 2 аргументов). В качестве альтернативы для этой цели можно использовать стандартные Comparator . Также можно использовать BiPredicate (это свяжет JUnit с Java-8, но добавит нестандартную логику И / ИЛИ / НЕ).
Пара замечаний по всему дальнейшему коду:

  • Имена BiMatcher , BiPredicate и Comparator будут использоваться как взаимозаменяемые.
  • Весь код не окончательный, а всего лишь общая идея.

Основные методы для добавления в класс Assert :

  • assertThat(T expected, T actual, Comparator<T> biMatcher);
  • assertThat(String message, T expected, T actual, Comparator<T> biMatcher); (возможно, необязательно, см. Ниже).
  • Несколько методов assertArray() (см. Ниже).

Мотивация: иногда нужно провести множество аналогичных проверок для партии объектов. Существующая функциональность позволяет это, но с большим количеством дополнительного кода (циклы и условия). С Comparator это можно сделать с меньшим количеством кода и с большей гибкостью.

Реальный пример (из которого я действительно начал думать об этой функции): нужно проверить, что все объекты в массиве одинаковы или не одинаковы (в зависимости от логического флага).

С текущими возможностями JUnit это будет выглядеть так:
короче:

for (int i = 0; i < elements.length - 1; i++) {
  if (checkSame) { // Same
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  } else { // Not same
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

лучшая производительность (но кого волнует производительность в тестах):

if (checkSame) { // Same
  for (int i = 0; i < elements.length - 1; i++) {
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  }
else { // Not same
  for (int i = 0; i < elements.length - 1; i++) {
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

Также мы можем реализовать собственный Comparator и использовать assertTrue()/assertFalse() , но код для создания компараторов также будет большим (если мы не используем лямбды).

С новым подходом код будет выглядеть намного короче и чище, как для меня, например:

Comparator<T> comparator = checkSame ? BiMatchers.same() : BiMatchers.notSame();
String message = checkSame ? "elements must be the same." : "elements must be not the same.";
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Чтобы сделать его еще короче, мы можем расширить Comparator до MessagedComparator с помощью необязательного свойства message , чтобы JUnit каким-то образом взял его оттуда. Нравится:

MessagedComparator<T> comparator = checkSame ? BiMatchers.same("elements must be the same.") : BiMatchers.notSame("elements must be not the same.");
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Последствия очень далеко идущие:
1) Класс Assert в целом будет очень гибким, потому что вы можете использовать любой стандартный или собственный компаратор без особого кода.
2) В результате предыдущего лямбда-выражения стало проще использовать для ввода любых условий.
3) Дополнительное логическое каскадирование (И, ИЛИ, НЕ) может быть добавлено из коробки (что-то похожее на org.hamcrest.CoreMatchers ). В настоящее время для любой новой мини-функции требуется новый метод, например assertNotSame() рядом с assertSame() и т. Д. Или нам снова нужны методы assertTrue()/assertFalse() .
4) Весь класс Assert может быть преобразован в единую форму. Только один пример:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(message, expected, actual, BiMatchers.same())
}

public static void assertThat(String message, T expected, T actual, Comparator<T> biMatcher) {
...
}

или как уже упоминалось:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(expected, actual, BiMatchers.same(message))
}

public static void assertThat(T expected, T actual, MessagedComparator<T> biMatcher) {
...
}

5) Могут быть добавлены методы assertArray() (таким образом, старые методы подвергнуты рефакторингу). Например:

public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
  assertArray(expecteds, actuals, BiMatchers.equals());
}

public static void assertArray(boolean[] expecteds, boolean[] actuals, Comparator<Boolean>) {
...
}

Так, например, вы можете проверить все элементы в 2 массивах так же просто, как:

Assert.assertArray(array1, array2, BiMatchers.same());

Также можно отдельно управлять проверками длины массива или другими проверками. Псевдокод:

Assert.assertArray(array1, array2, and(sameLength(), same()));

Все 9 Комментарий

Спасибо, что подняли этот вопрос.

Я бы предпочел, чтобы JUnit 4.x не добавлял больше утверждений DSL. Действительно сложно получить правильный и гибкий DSL, и я не уверен, что имеет смысл тратить время и силы на это в JUnit, когда есть хорошие сторонние структуры утверждений, такие как Truth или Fest.

Кроме того, функции, требующие Java 8, должны находиться на http://github.com/junit-team/junit5.

@gitIvanB Спасибо, что открыли вопрос. Как и @kcooney , я также думаю, что эту

@kcooney , @marcphilipp , спасибо за
Еще один вопрос. Могу ли я использовать как практическое правило, что использование Assert устарело (или не рекомендуется)? Особенно с учетом будущего возможного обновления с JUnit-4 до JUnit-5.

@gitIvanB Вопрос немного непонятный. При разработке на junit4 используется org.junit.Assert , при разработке на junit5 - org.junit.jupiter.api.Assertions

Рекомендуемый подход - статический импорт методов из него, чтобы избежать наличия Assert. в каждой строке.

@gitIvanB Вам определенно не следует использовать junit.framework.Assert , но org.junit.Assert в порядке. При обновлении вы можете использовать IDE для преобразования JUnit 4 в утверждения JUnit Jupiter (IDEA уже поддерживает это). Самая большая разница в том, что необязательный параметр сообщения идет первым в JUnit 4, но последним в Jupiter. В качестве альтернативы вы можете решить использовать другую библиотеку утверждений сейчас и продолжать использовать ее при переходе с Vintage на Jupiter.

@panchenko , @marcphilipp. Как я понял, org.junit.Assert JUnit-4 запечатаны и не будут обогащаться новыми методами. В JUnit-5 мне нужно использовать либо org.junit.jupiter.api.Assertions (как замену org.junit.Assert ), или некоторую библиотеку утверждений.
Мне нужно время, чтобы изучить JUnit-5, но с первого взгляда на org.junit.jupiter.api.Assertions кажется, что его подход в целом похож на org.junit.Assert . Так что велика вероятность, что мне понадобится создать аналогичный билет для JUnit-5 :) Я считаю, что JUnit-5 должен либо предоставлять полноценные утверждения, либо полностью делегировать их библиотекам утверждений.

@gitIvanB Философия JUnit - предоставить хорошую расширяемую структуру для написания тестов для Java на Java. Будучи расширяемой средой, мы часто видим, что другие проекты с открытым исходным кодом расширяют ее и / или предоставляют богатые библиотеки тестирования, которые можно использовать с JUnit.

Что касается утверждений, существует несколько проектов, которые предоставляют более богатый набор утверждений, иногда с возможностью расширения.
Например, есть Google Truth (https://github.com/google/truth), FEST (https://github.com/alexruiz/fest-assert-2.x), AssertJ (http: // joel- costigliola.github.io/assertj/) и Hamcrest (http://hamcrest.org/JavaHamcrest/).

Поскольку существует так много замечательных библиотек утверждений, я неохотно принимал запросы на новые функции для org.junit.Assert . Я бы не стал считать его замороженным (хотя я бы посчитал замороженным junit.framework.Assert ). Фактически, 4.13 представит assertThrows . Но поскольку у нас никогда не будет такого богатого набора утверждений, как у этих проектов, мы чувствуем себя комфортно, предоставляя основы.

Другими словами, сообщества здоровья сформировались вокруг использования и поддержки этих проектов, поэтому я думаю, что мы должны принять и поддержать их.

Я не могу говорить о JUnit5, но я полагаю, что первоначальные разработчики чувствовали, что они не могут выпустить следующее поколение JUnit без хорошей основы методов утверждения (или, возможно, они считали, что это лучший способ гарантировать, что новый фреймворк работает и отполированный был для тестирования JUnit5 с помощью JUnit5). Новые методы программирования заставили их принимать разные решения о том, как будет выглядеть базовый API утверждений, чем это делали Кент, Эрих и Дэвид, поэтому вы увидите некоторые различия. Но вы, вероятно, никогда не увидите в JUnit такого богатого набора утверждений, как в Hamcrest, или в расширяемом DSL, таком как Truth.

Я оставляю команде JUnit5 решать, какие типы изменений они будут учитывать. Если вы уверены, что
методы, которые вы предлагаете, важны как основа для написания хороших тестов, не стесняйтесь создавать там проблемы.

Когда мы начали работу над JUnit 5 (в то время под кодовым названием «JUnit Lambda»), мы обсудили масштабы того, чего мы хотели достичь. Было решено, что написание нового типа библиотеки утверждений не входит в сферу охвата.

Или, как сказано в Руководстве пользователя JUnit 5 :

Несмотря на то, что средства утверждения, предоставляемые JUnit Jupiter, достаточны для многих сценариев тестирования, бывают случаи, когда желательно или требуется больше мощности и дополнительных функций, таких как сопоставители. В таких случаях команда JUnit рекомендует использовать сторонние библиотеки утверждений, такие как AssertJ, Hamcrest, Truth и т. Д. Разработчики могут свободно использовать библиотеку утверждений по своему выбору.

Таким образом, он тоже не заморожен, но цель аналогична JUnit 4, а именно предоставить базовый набор утверждений для запуска пользователей. Мы даже используем AssertJ для наших собственных модульных тестов.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги