AssertJ: тестирование исключений с сообщениями, сгенерированными с помощью String.format

Мне интересно, есть ли чистый и полный способ утверждения сообщения, прикрепленного к выброшенному исключению, когда это сообщение было сгенерировано с использованием String.format(). Например, такой класс:

public class Car {

  public static final String DRIVE_ERROR = "Can't drive while car %s is parked!";

  private String name;
  private boolean parked;

  public Car(String name) {
    this.name = name;
    this.parked = true;
  }

  public void drive() {
    if (parked) {
      throw new IllegalStateException(String.format(DRIVE_ERROR, name));
    }
  }
}

(Извините за странный пример, просто пытаюсь сделать его как можно более простым). Теперь, если бы я тестировал машину, у меня был бы такой класс:

public class CarTest {

  @Test
  public void drive_test() {
    Car car = new Car("Greased Lightning");
    assertThatThrownBy(() -> car.drive())
        .isInstanceOf(IllegalStateException.class)
        .hasMessageContaining("???");
  }
}

Вопрос в том, как лучше всего утверждать сообщение? В этом примере я мог бы отделить объявление имени автомобиля, а затем использовать формат String, чтобы получить статическую строку из Car и отформатировать имя, но это выглядит как много лишнего кода и не может быть легко используется во многих случаях (например, когда элемент, который входит в отформатированную строку, определяется во время выполнения). Что я действительно хотел бы сделать, так это передать строку сообщения об ошибке в hasMessageContaining и заставить его игнорировать заполнитель "%s" и принимать что-либо в этом месте. Есть ли способ выполнить сопоставление регулярных выражений строк с помощью assertJ? Или какой-то другой способ сделать это чисто?

РЕДАКТИРОВАТЬ: я также открыт для альтернативных исключений с сообщениями, которые легче тестировать. Одним из решений является просто использование конкатенации строк, например throw new Exception(STATIC_ERROR_MESSAGE + name), а затем проверка того, что сообщение содержит первую часть, но это действительно ограничивает ваши возможности форматирования сообщения и выглядит не очень чистым.


person EaterOfFromage    schedule 15.10.2018    source источник


Ответы (1)


Утверждения сообщения об исключении ограничены по сравнению с обычным утверждением String. Что вы можете сделать, так это использовать matches или containsPattern утверждения, например:

@Test
public void test() {
  // GIVEN some preconditions

  // WHEN
  Throwable thrown = catchThrowableOfType(() -> { throw new IllegalStateException("boom!"); }, 
                                         IllegalStateException.class);
  // THEN
  assertThat(thrown.getMessage()).matches(".oo.")
                                 .containsPattern("oo.");
  // or even better thanks to Rolland Illig suggestion
  assertThat(thrown).hasMessageMatching(".oo.");

}

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

person Joel Costigliola    schedule 19.10.2018
comment
Разве hasMessageMatching уже не существует? Я нашел его в AbstractThrowableAssertions. - person Roland Illig; 20.10.2018
comment
Я просто не мог поверить, что в столь хорошо спроектированной библиотеке можно было забыть об этой функции, поэтому я перепроверил. :) - person Roland Illig; 20.10.2018
comment
Красивый! Спасибо! - person EaterOfFromage; 24.10.2018