Asserções na JUnit 4 e JUnit 5

Asserções na JUnit 4 e JUnit 5

1. Introdução

Neste artigo, vamos explorar em detalhes as asserções disponíveis no JUnit.

Seguindo os artigosmigrating from JUnit 4 to JUnit 5eA Guide to JUnit 5, agora entraremos em detalhes sobre as diferentes afirmações disponíveis no JUnit 4 e JUnit 5.

Também destacaremos as melhorias feitas nas afirmações com o JUnit 5.

2. Asserções

Assertions are utility methods to support asserting conditions in tests; esses métodos são acessíveis por meio da classeAssert, na JUnit 4, e da classeAssertions, na JUnit 5.

Para aumentar a legibilidade do teste e das próprias afirmações, é sempre recomendadoimport estaticamente a respectiva classe. Dessa maneira, podemos nos referir diretamente ao próprio método de asserção sem a classe de representação como prefixo.

Vamos começar a explorar as asserções disponíveis com JUnit 4.

3. Asserções na JUnit 4

Nesta versão da biblioteca, as asserções estão disponíveis para todos os tipos primitivos,Objects,earrays (tanto dos primitivos quantoObjects).

A ordem dos parâmetros, dentro da asserção, é o valor esperado seguido pelo valor real; opcionalmente, o primeiro parâmetro pode ser uma mensagemString que representa a saída da mensagem da condição avaliada.

Há apenas uma ligeiramente diferente em como são definidas as afirmações deassertThat, mas vamos cobrir isso mais tarde.

Vamos começar com oassertEquals um.

3.1. assertEquals

A afirmaçãoassertEquals verifica se os valores esperados e reais são iguais:

@Test
public void whenAssertingEquality_thenEqual() {
    String expected = "example";
    String actual = "example";

    assertEquals(expected, actual);
}

Também é possível especificar uma mensagem a ser exibida quando a declaração falhar:

assertEquals("failure - strings are not equal", expected, actual);

3.2. assertArrayEquals

Se quisermos afirmar que dois arrays são iguais, podemos usar oassertArrayEquals:

@Test
public void whenAssertingArraysEquality_thenEqual() {
    char[] expected = {'J','u','n','i','t'};
    char[] actual = "Junit".toCharArray();

    assertArrayEquals(expected, actual);
}

Se as duas matrizes foremnull, a asserção as considerará iguais:

@Test
public void givenNullArrays_whenAssertingArraysEquality_thenEqual() {
    int[] expected = null;
    int[] actual = null;

    assertArrayEquals(expected, actual);
}

3.3. assertNotNull eassertNull

Quando queremos testar se um objeto énull, podemos usar a afirmaçãoassertNull:

@Test
public void whenAssertingNull_thenTrue() {
    Object car = null;

    assertNull("The car should be null", car);
}

Da maneira oposta, se quisermos afirmar que um objeto não deve ser nulo, podemos usar oassertNotNull assertion.

3.4. assertNotSame eassertSame

ComassertNotSame, é possível verificar se duas variáveis ​​não se referem ao mesmo objeto:

@Test
public void whenAssertingNotSameObject_thenDifferent() {
    Object cat = new Object();
    Object dog = new Object();

    assertNotSame(cat, dog);
}

Caso contrário, quando quisermos verificar se duas variáveis ​​se referem ao mesmo objeto, podemos usar a asserçãoassertSame.

3.5. assertTrue eassertFalse

Caso desejemos verificar se uma determinada condição étrue oufalse, podemos usar respectivamente a asserçãoassertTrue ouassertFalse:

@Test
public void whenAssertingConditions_thenVerified() {
    assertTrue("5 is greater then 4", 5 > 4);
    assertFalse("5 is not greater then 6", 5 > 6);
}

3.6. fail

A asserçãofail falha em um teste lançando umAssertionFailedError. Ele pode ser usado para verificar se uma exceção real é lançada ou quando queremos que um teste falhe durante seu desenvolvimento.

Vamos ver como podemos usá-lo no primeiro cenário:

@Test
public void whenCheckingExceptionMessage_thenEqual() {
    try {
        methodThatShouldThrowException();
        fail("Exception not thrown");
    } catch (UnsupportedOperationException e) {
        assertEquals("Operation Not Supported", e.getMessage());
    }
}

3.7. assertThat

A asserçãoassertThat é a única na JUnit 4 que tem uma ordem reversa dos parâmetros em comparação com as outras asserções.

Nesse caso, a asserção tem uma mensagem de falha opcional, o valor real e um objetoMatcher.

Vamos ver como podemos usar essa afirmação para verificar se uma matriz contém valores específicos:

@Test
public void testAssertThatHasItems() {
    assertThat(
      Arrays.asList("Java", "Kotlin", "Scala"),
      hasItems("Java", "Kotlin"));
}

Informações adicionais, sobre o uso poderoso da afirmaçãoassertThat com o objetoMatcher, estão disponíveis emTesting with Hamcrest.

4. JUnit 5 Assertions

O JUnit 5 manteve muitos dos métodos de asserção do JUnit 4, enquanto adicionava alguns novos que aproveitam o suporte ao Java 8.

Também nesta versão da biblioteca, asserções estão disponíveis para todos os tipos primitivos,Objects,e arrays (tanto de primitivos quanto de Objetos).

A ordem dos parâmetros das asserções foi alterada, movendo o parâmetro da mensagem de saída como o último parâmetro. Graças ao suporte do Java 8, a mensagem de saída pode ser umSupplier, permitindo uma avaliação preguiçosa dele.

Vamos começar a revisar as afirmações disponíveis também no JUnit 4.

4.1. assertArrayEquals

A asserçãoassertArrayEquals verifica se as matrizes esperadas e reais são iguais:

@Test
public void whenAssertingArraysEquality_thenEqual() {
    char[] expected = { 'J', 'u', 'p', 'i', 't', 'e', 'r' };
    char[] actual = "Jupiter".toCharArray();

    assertArrayEquals(expected, actual, "Arrays should be equal");
}

Se as matrizes não forem iguais, a mensagem “Arrays should be equal” será exibida como saída.

4.2. assertEquals

No caso de desejarmos afirmar que doisfloats são iguais, podemos usar a asserçãoassertEquals simples:

@Test
public void whenAssertingEquality_thenEqual() {
    float square = 2 * 2;
    float rectangle = 2 * 2;

    assertEquals(square, rectangle);
}

No entanto, se quisermos afirmar que o valor real difere em um delta predefinido do valor esperado, ainda podemos usarassertEquals, mas temos que passar o valor delta como o terceiro parâmetro:

@Test
public void whenAssertingEqualityWithDelta_thenEqual() {
    float square = 2 * 2;
    float rectangle = 3 * 2;
    float delta = 2;

    assertEquals(square, rectangle, delta);
}

4.3. assertTrue eassertFalse

Com a afirmação deassertTrue, é possível verificar se as condições fornecidas sãotrue:

@Test
public void whenAssertingConditions_thenVerified() {
    assertTrue(5 > 4, "5 is greater the 4");
    assertTrue(null == null, "null is equal to null");
}

Graças ao suporte da expressão lambda, é possível fornecer umBooleanSupplier para a asserção em vez de uma condiçãoboolean.

Vamos ver como podemos afirmar a exatidão de umBooleanSupplier usando a asserçãoassertFalse:

@Test
public void givenBooleanSupplier_whenAssertingCondition_thenVerified() {
    BooleanSupplier condition = () -> 5 > 6;

    assertFalse(condition, "5 is not greater then 6");
}

4.4. assertNull eassertNotNull

Quando queremos afirmar que um objeto não énull, podemos usar a asserçãoassertNotNull:

@Test
public void whenAssertingNotNull_thenTrue() {
    Object dog = new Object();

    assertNotNull(dog, () -> "The dog should not be null");
}

De maneira oposta, podemos usar a asserçãoassertNull para verificar se o real énull:

@Test
public void whenAssertingNull_thenTrue() {
    Object cat = null;

    assertNull(cat, () -> "The cat should be null");
}

Em ambos os casos, a mensagem de falha será recuperada de forma lenta, pois é umSupplier.

4.5. assertSame eassertNotSame

Quando queremos afirmar que o esperado e o real se referem ao mesmoObject, devemos usar a afirmaçãoassertSame:

@Test
public void whenAssertingSameObject_thenSuccessfull() {
    String language = "Java";
    Optional optional = Optional.of(language);

    assertSame(language, optional.get());
}

De maneira oposta, podemos usar oassertNotSame.

4.6. fail

A afirmaçãofail falha em um teste com a mensagem de falha fornecida, bem como a causa subjacente. Isso pode ser útil para marcar um teste quando seu desenvolvimento não foi concluído:

@Test
public void whenFailingATest_thenFailed() {
    // Test not completed
    fail("FAIL - test not completed");
}

4.7. assertAll

Uma das novas afirmações introduzidas na JUnit 5 éassertAll.

Essa asserção permite a criação de asserções agrupadas, nas quais todas as asserções são executadas e suas falhas são relatadas juntas. Em detalhes, esta afirmação aceita um título, que será incluído na string da mensagem para oMultipleFailureError, e umStream deExecutable.

Vamos definir uma afirmação agrupada:

@Test
public void givenMultipleAssertion_whenAssertingAll_thenOK() {
    assertAll(
      "heading",
      () -> assertEquals(4, 2 * 2, "4 is 2 times 2"),
      () -> assertEquals("java", "JAVA".toLowerCase()),
      () -> assertEquals(null, null, "null is equal to null")
    );
}

A execução de uma asserção agrupada é interrompida apenas quando um dos executáveis ​​lança uma exceção na lista negra (OutOfMemoryError por exemplo).

4.8. assertIterableEquals

OassertIterableEquals afirma que os iteráveis ​​esperados e reais são profundamente iguais.

Para serem iguais, ambos os iteráveis ​​devem retornar elementos iguais na mesma ordem e não é necessário que os dois iteráveis ​​sejam do mesmo tipo para serem iguais.

Com esta consideração, vamos ver como podemos afirmar que duas listas de tipos diferentes (LinkedList eArrayList, por exemplo) são iguais:

@Test
public void givenTwoLists_whenAssertingIterables_thenEquals() {
    Iterable al = new ArrayList<>(asList("Java", "Junit", "Test"));
    Iterable ll = new LinkedList<>(asList("Java", "Junit", "Test"));

    assertIterableEquals(al, ll);
}

Da mesma forma que oassertArrayEquals, se ambos os iteráveis ​​forem nulos, são considerados iguais.

4.9. assertLinesMatch

OassertLinesMatch afirma que a lista esperada deString corresponde à lista real.

Este método difere dosassertEqualseassertIterableEquals, pois, para cada par de linhas esperadas e reais, ele executa este algoritmo:

  1. verifique se a linha esperada é igual à linha real. Se sim, continua com o próximo par

  2. trate a linha esperada como uma expressão regular e execute uma verificação com o métodoString.matches(). Se sim, continua com o próximo par

  3. verifique se a linha esperada é um marcador de avanço rápido. Se sim, aplique o avanço rápido e repita o algoritmo da etapa 1

Vamos ver como podemos usar essa afirmação para afirmar que duas listas deString têm linhas correspondentes:

@Test
public void whenAssertingEqualityListOfStrings_thenEqual() {
    List expected = asList("Java", "\\d+", "JUnit");
    List actual = asList("Java", "11", "JUnit");

    assertLinesMatch(expected, actual);
}

4.10. assertNotEquals

Complementar aoassertEquals, a afirmaçãoassertNotEquals afirma que os valores esperados e reais não são iguais:

@Test
public void whenAssertingEquality_thenNotEqual() {
    Integer value = 5; // result of an algorithm

    assertNotEquals(0, value, "The result cannot be 0");
}

Se ambos foremnull, a declaração falha.

4.11. assertThrows

Para aumentar a simplicidade e a legibilidade, a nova asserçãoassertThrows nos permite uma maneira clara e simples de afirmar se um executável lança o tipo de exceção especificado.

Vamos ver como podemos declarar uma exceção lançada:

@Test
void whenAssertingException_thenThrown() {
    Throwable exception = assertThrows(
      IllegalArgumentException.class,
      () -> {
          throw new IllegalArgumentException("Exception message");
      }
    );
    assertEquals("Exception message", exception.getMessage());
}

A asserção falhará se nenhuma exceção for lançada ou se uma exceção de um tipo diferente for lançada.

4.12. assertTimeout e assertTimeoutPreemptively

No caso de querermos afirmar que a execução de umExecutable fornecido termina antes de um determinadoTimeout, podemos usar a afirmaçãoassertTimeout:

@Test
public void whenAssertingTimeout_thenNotExceeded() {
    assertTimeout(
      ofSeconds(2),
      () -> {
        // code that requires less then 2 minutes to execute
        Thread.sleep(1000);
      }
    );
}

Porém, com a asserçãoassertTimeout, o executável fornecido será executado na mesma thread do código de chamada. Consequentemente, a execução do fornecedor não será abortada preventivamente se o tempo limite for excedido.

Caso desejemos ter certeza de que a execução do executável será abortada ao ultrapassar o tempo limite, podemos usar a asserçãoassertTimeoutPreemptively.

Ambas as asserções podem aceitar, em vez deExecutable, aThrowingSupplier, representando qualquer bloco genérico de código que retorna um objeto e que pode potencialmente lançar umThrowable.

5. Conclusão

Neste tutorial, abordamos todas as asserções disponíveis no JUnit 4 e no JUnit 5.

Destacamos brevemente as melhorias feitas no JUnit 5, com a introdução de novas asserções e o apoio de lambdas.

Como sempre, o código-fonte completo deste artigo está disponívelover on GitHub.