Можете ли вы добавить собственное сообщение в AssertJ assertThat?
У нас есть набор тестов, который в основном использует утверждения JUnit с сопоставителями Hamcrest. Одна из нашей команды начала экспериментировать с AssertJ и поразила людей его синтаксисом, гибкостью и декларативностью. Есть одна особенность, которую предоставляет JUnit, для которой я не могу найти эквивалент в AssertJ: добавление специального сообщения об ошибке подтверждения.
Мы часто сравниваем объекты, которые не созданы для удобочитаемости человека и будут иметь случайные идентификаторы или идентификаторы UUID, и невозможно определить, какими они должны быть по данным, которые они содержат. К сожалению, это неизбежная ситуация для нашей кодовой базы, поскольку одной из целей, которые она выполняет, является сопоставление данных между другими службами без необходимости понимания, что это такое.
В Юните assertThat
Метод предоставляет версию с String reason
параметр перед Matcher<T>
пары. Это упрощает добавление короткой строки отладки, проливающей некоторый свет на проблему, например, то, что сравнение должно означать для человека.
AssertJ, с другой стороны, предоставляет миллион различных обобщенных static assertThat
методы, которые возвращают некоторую форму интерфейса Assert или один из множества реализующих его классов. Этот интерфейс не предоставляет стандартного способа настройки настраиваемого сообщения для включения в него при сбоях.
Есть ли способ получить эту функциональность из AssertJ API или одного из его расширений, не создавая собственный класс assert для каждого типа assert, к которому мы хотим добавить сообщения?
5 ответов
И в классической моде я нашел то, что искал, сразу после публикации вопроса. Надеюсь, это облегчит поиск следующего человека без необходимости знать, как он называется. Волшебный метод обманчиво кратко as
, который является частью другого интерфейса, который AbstractAssert
Реализует: Описано, а не базовый интерфейс Assert.
public S as(String description, Object... args)
Устанавливает описание поддержки этого объекта
String.format(String, Object...)
синтаксис.
Пример:try { // set a bad age to Mr Frodo which is really 33 years old. frodo.setAge(50); // you can specify a test description with as() method or describedAs(), it supports String format args assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33); } catch (AssertionError e) { assertThat(e).hasMessage("[check Frodo's age] expected:<[33]> but was:<[50]>"); }
Где эта строка в кавычках в блоке catch hasMessage
это то, что появляется в журнале вывода вашего модульного теста, если утверждение не выполнено
Я нашел это, заметив failWithMessage
помощник в пользовательской странице подтверждения, связанной в вопросе. JavaDoc для этого метода указывает на то, что он защищен, поэтому вызывающие его не могут использовать для установки пользовательского сообщения. Однако упоминается as
помощник:
Кроме того, этот метод учитывает любое описание, установленное с
as(String, Object...)
или переопределенное сообщение об ошибке, определенное пользователем сoverridingErrorMessage(String, Object...)
,
... и помощник overridingErrorMessage, который полностью заменяет стандартный AssertJ expected: ... but was:...
сообщение с новой строкой.
На домашней странице AssertJ не упоминается ни один из помощников, пока не будет выделена страница функций, на которой показаны примеры as
помощник в разделе Soft Assertions, но не описывает напрямую, что он делает.
Чтобы добавить еще один вариант ответа Патрика М:
Вместо того, чтобы использовать Descriptable.as
Вы также можете использовать AbstractAssert.withFailMessage()
:
try {
// set a bad age to Mr Frodo which is really 33 years old.
frodo.setAge(50);
// you can specify a test description via withFailMessage(), supports String format args
assertThat(frodo.getAge()).
withFailMessage("Frodo's age is wrong: %s years, difference %s years",
frodo.getAge(), frodo.getAge()-33).
isEqualTo(33);
} catch (AssertionError e) {
assertThat(e).hasMessage("Frodo's age is wrong: 50 years, difference 17 years");
}
Разница в использовании Descriptable.as
в том, что он дает вам полный контроль над пользовательским сообщением - здесь нет "ожидаемого" и "но было".
Это полезно, когда проверяемые фактические значения бесполезны для представления - этот метод позволяет вместо этого показывать другие, возможно, рассчитанные значения или вообще не показывать их.
Обратите внимание, что так же, как Descriptable.as
Вы должны позвонить withFailMessage()
перед любыми фактическими утверждениями - иначе это не сработает, так как утверждение сработает первым. Это отмечено в Javadoc.
На данный момент упомянуты две опции и , поэтому я не буду снова вдаваться в синтаксис или использование. Чтобы увидеть разницу между ними и то, чем каждый из них может быть полезен, рассмотрим вариант использования, когда мы тестируем экспортируемые метрики:
// map of all metrics, keyed by metrics name
Map<String, Double> invocations = ...
List.of(
"grpc.client.requests.sent",
"grpc.client.responses.received",
"grpc.server.requests.received",
"grpc.server.responses.sent"
).forEach { counter ->
var meter = // create meter name using counter
assertThat(invocations)
.withFailMessage("Meter %s is not found", meter)
.containsKey(meter)
assertThat(invocations.get(meter))
.as(meter)
.isEqualTo(0.0)
}
Я использовал синтаксис Java 11, чтобы уменьшить некоторые шаблоны.
Без , если счетчик отсутствует на карте, выходные данные по умолчанию содержат дамп всех записей на карте, что загромождает журнал тестирования. Нас не волнует, какие другие счетчики присутствуют, только то, что там есть тот, который мы хотим.
С использованием
withFailMessage
, вывод становится:
java.lang.AssertionError: Meter blah is not found
Что касается
as
, он только добавляет заданное сообщение к выходным данным, но сохраняет неудачное сравнение, что очень полезно. Мы получаем:
org.opentest4j.AssertionFailedError: [blah]
Expecting:
<1.0>
to be equal to:
<0.0>
but was not.
Используйте встроенный
as()
метод в AssertJ. Например:
assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
К вашему сведению, это задокументировано на новом веб-сайте AssertJ (который все еще находится в стадии разработки, но уже содержит полезную информацию), см. https://assertj.github.io/doc/.