Czy możesz dodać niestandardową wiadomość do AssertJ assertThat?

90

Mamy zestaw testów, który używa głównie asercji JUnit z dopasowywaniem Hamcrest. Jeden z naszych zespołów zaczął eksperymentować z AssertJ i zaimponował ludziom jego składnią, elastycznością i deklaratywnością. Jest jedna funkcja, którą JUnit zapewnia, a której nie mogę znaleźć odpowiednika w AssertJ: dodanie niestandardowego komunikatu o błędzie potwierdzenia.

Często porównujemy obiekty, które nie są przeznaczone do czytelności dla ludzi i będą miały losowo wyglądające identyfikatory lub identyfikatory UUID, a na podstawie zawartych w nich danych nie można stwierdzić, jakie mają być. Jest to sytuacja nieunikniona dla naszej bazy kodu, niestety, ponieważ część celu, który spełnia, polega na mapowaniu danych między innymi usługami, niekoniecznie rozumiejąc, co to jest.

W JUnit assertThatmetoda udostępnia wersję z String reasonparametrem przed Matcher<T>parametrem. To sprawia, że ​​dodanie krótkiego ciągu diagnostycznego rzucającego trochę światła na problem, na przykład, co to porównanie powinno oznaczać dla człowieka, jest trywialne.

Z drugiej strony, AssertJ udostępnia mnóstwo różnych uogólnionychstatic assertThat metod, które zwracają jakąś formę interfejsu Assert lub jedną z wielu klas implementujących. Ten interfejs nie zapewnia standardowego sposobu ustawiania niestandardowego komunikatu, który ma być dołączany do błędów.

Czy istnieje sposób, aby uzyskać tę funkcjonalność z API AssertJ lub jednego z jego rozszerzeń bez konieczności tworzenia niestandardowej klasy assert dla każdego typu potwierdzenia, do którego chcemy dodać komunikaty?

Patrick M.
źródło

Odpowiedzi:

137

I w klasyczny sposób znalazłem to, czego szukałem chwilę po zadaniu pytania. Miejmy nadzieję, że ułatwi to kolejnej osobie znalezienie jej bez uprzedniego poznania jej nazwy. Magiczna metoda to zwodniczo krótka nazwa as, która jest częścią innego interfejsu, który AbstractAssertimplementuje: Descriptable , a nie podstawowy interfejs Assert.

public S as(String description, Object... args)

Ustawia opis tego obiektu obsługującego String.format(String, Object...)składnię.
Przykład:

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

Gdzie ten cytowany w cudzysłowie ciąg w bloku catch hasMessagejest tym, co pojawia się w dzienniku wyjściowym testu jednostkowego, jeśli potwierdzenie nie powiedzie się.


Znalazłem to, zauważając failWithMessagepomocnika na stronie potwierdzenia niestandardowego do której prowadzi pytanie. Dokument JavaDoc dla tej metody wskazuje, że jest ona chroniona, więc wywołujące nie mogą jej używać do ustawiania niestandardowego komunikatu. Wspomina jednak aspomocnika:

Ponadto ta metoda honoruje każdy opis ustawiony z as(String, Object...) lub nadpisany komunikat o błędzie zdefiniowany przez użytkownika za pomocą overridingErrorMessage(String, Object...).

... i pomocnik overridingErrorMessage , który całkowicie zastępuje standardowy expected: ... but was:...komunikat AssertJ dostarczonym nowym ciągiem.

Strona domowa AssertJ nie wspomina żadnego pomocnika, dopóki nie pojawi się strona z wyróżnionymi funkcjami, która pokazuje przykłady aspomocnika w sekcji Soft Assertions , ale nie opisuje bezpośrednio, co robi.

Patrick M.
źródło
22

Aby dodać kolejną opcję do odpowiedzi Patricka M:

Zamiast używać Descriptable.as, możesz również użyć 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");
}

Różnica w stosunku do używania Descriptable.aspolega na tym, że zapewnia pełną kontrolę nad niestandardową wiadomością - nie ma „oczekiwanych” ani „ale było”.

Jest to przydatne, gdy rzeczywiste wartości testowane nie są przydatne do prezentacji - ta metoda pozwala zamiast tego pokazać inne, prawdopodobnie obliczone wartości, lub w ogóle ich nie pokazać.


Zauważ, że tak jak Descriptable.asmusisz zadzwonić withFailMessage() przed jakimikolwiek faktycznymi asercjami - w przeciwnym razie to nie zadziała, ponieważ asercja zostanie uruchomiona jako pierwsza. Jest to odnotowane w Javadoc.

sleske
źródło
2
„musisz zadzwonić z withFailMessage () przed jakimikolwiek faktycznymi asercjami” dzięki, to mnie zaskoczyło . Kolejność wywoływania withFailMessagesprawy; Lubię AssertJ, ale to jest do bani.
Abhijit Sarkar
0

Użyj wbudowanej as()metody w AssertJ. Na przykład:

 assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
Testilla
źródło