AssertJ:使用String.format生成的消息测试异常

时间:2018-10-15 14:49:47

标签: java junit assertj

我想知道当使用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)之类的String串联,然后测试消息是否包含第一部分,但这确实限制了消息的格式化能力,而且看起来不太干净。

1 个答案:

答案 0 :(得分:1)

与常规String断言相比,异常消息断言受到限制。 您可以做的是使用matchescontainsPattern断言,例如:

@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,您不必再检查所捕获的异常是否属于预期的类型。