Você pode adicionar uma mensagem personalizada para AssertJ assertThat?

93

Temos um conjunto de testes que usa principalmente asserções JUnit com matchers Hamcrest. Um membro de nossa equipe começou a experimentar o AssertJ e impressionou as pessoas com sua sintaxe, flexibilidade e declaratividade. Há um recurso que o JUnit fornece para o qual não consigo encontrar um equivalente em AssertJ: adicionar uma mensagem de falha de declaração personalizada.

Frequentemente comparamos objetos que não são feitos para serem lidos por humanos e terão Ids ou UUIDs de aparência aleatória e é impossível dizer o que eles deveriam ser pelos dados que contêm. Esta é uma situação inevitável para nossa base de código, infelizmente, como parte do propósito que ela cumpre é mapear dados entre outros serviços sem necessariamente entender o que é.

No JUnit, o assertThatmétodo fornece uma versão com um String reasonparâmetro antes doMatcher<T> param. Isso torna trivial adicionar uma string de depuração curta para esclarecer o problema, como o que a comparação deve significar para um ser humano.

O AssertJ, por outro lado, fornece um milhão de métodos genéricosstatic assertThat diferentes que retornam alguma forma de interface Assert ou uma de suas muitas classes de implementação. Essa interface não fornece uma maneira padrão de definir uma mensagem personalizada a ser incluída com as falhas.

Existe alguma maneira de obter essa funcionalidade da API AssertJ ou uma de suas extensões sem ter que criar uma classe assert customizada para cada tipo de declaração ao qual queremos adicionar mensagens?

Patrick M
fonte

Respostas:

139

E de forma clássica, encontrei o que procurava momentos depois de postar a pergunta. Esperançosamente, isso tornará mais fácil para a próxima pessoa encontrar, sem primeiro precisar saber como se chama. O método mágico tem um nome enganosamente curto as, que faz parte de outra interface que AbstractAssertimplementa: Descriptable , não a interface Assert básica.

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

Define a descrição deste objeto que suporta a String.format(String, Object...)sintaxe.
Exemplo:

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

Onde essa string entre aspas no bloco catch hasMessageé o que aparece no log de saída do teste de unidade se a declaração falhar.


Eu descobri isso observando o failWithMessageajudante na página de declaração personalizada vinculada à pergunta. O JavaDoc para esse método indica que ele é protegido, portanto, não pode ser usado por chamadores para definir uma mensagem personalizada. No entanto, menciona o asajudante:

Além disso, este método honra qualquer descrição definida com as(String, Object...)ou mensagem de erro substituída definida pelo usuário com overridingErrorMessage(String, Object...).

... eo overridingErrorMessage ajudante, que substitui completamente o AssertJ padrão expected: ... but was:...mensagem com a nova cadeia fornecido.

A página inicial do AssertJ não menciona nenhum dos auxiliares até a página de destaque dos recursos, que mostra exemplos do asauxiliar na seção Soft Assertions , mas não descreve diretamente o que ele faz.

Patrick M
fonte
25

Para adicionar outra opção à resposta de Patrick M:

Em vez de usar Descriptable.as, você também pode usar 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");
}

A diferença de usar Descriptable.asé que oferece controle total sobre a mensagem personalizada - não há "esperado" e "mas era".

Isso é útil quando os valores reais sendo testados não são úteis para apresentação - este método permite que você mostre outros valores possivelmente calculados, ou nenhum.


Observe que, assim como Descriptable.as, você deve chamar withFailMessage() antes de qualquer asserção real - caso contrário, não funcionará, pois a asserção será acionada primeiro. Isso é observado no Javadoc.

Sleske
fonte
4
"você deve chamar withFailMessage () antes de qualquer asserção real" obrigado, isso me enganou . A ordem de chamada withFailMessageimporta; Eu gosto de AssertJ, mas isso é uma merda.
Abhijit Sarkar
0

Use o as()método embutido em AssertJ. Por exemplo:

 assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
Testilla
fonte