Métodos de simulação de Mockito

Métodos de simulação de Mockito

1. Visão geral

Este tutorial ilustra vários usos dos métodosmock estáticos padrão da APIMockito.

Tal como acontece com outros artigos focados no framework Mockito (comoMockito Verify ouMockito When/Then), a classeMyList mostrada abaixo será usada como o colaborador a ser simulado em casos de teste:

public class MyList extends AbstractList {
    @Override
    public String get(int index) {
        return null;
    }

    @Override
    public int size() {
        return 1;
    }
}

2. Zombaria simples

A variante sobrecarregada mais simples do métodomock é aquela com um único parâmetro para a classe a ser simulada:

public static  T mock(Class classToMock)

Usaremos esse método para zombar de uma classe e definir uma expectativa:

MyList listMock = mock(MyList.class);
when(listMock.add(anyString())).thenReturn(false);

Em seguida, execute um método no mock:

boolean added = listMock.add(randomAlphabetic(6));

O código a seguir confirma que o métodoadd foi invocado na simulação e que a invocação retorna um valor que corresponde à expectativa que definimos antes:

verify(listMock).add(anyString());
assertThat(added, is(false));

3. Zombando com o nome de mock

Nesta seção, cobriremos outra variante do métodomock que é fornecida com um argumento especificando o nome da simulação:

public static  T mock(Class classToMock, String name)

De um modo geral, o nome de um mock não tem nada a ver com o código de trabalho, mas pode ser útil quando se trata de depuração, onde o nome do mock é usado para rastrear erros de verificação.

Para garantir que o nome fornecido de um mock seja incluído na mensagem de uma exceção lançada de uma verificação malsucedida, contaremos com uma implementação JUnit da interfaceTestRule, chamadaExpectedException, e a incluiremos em uma aula de teste:

@Rule
public ExpectedException thrown = ExpectedException.none();

Esta regra será usada para lidar com exceções geradas pelos métodos de teste.

No código a seguir, criamos uma simulação para a classeMyList e a nomeamosmyMock:

MyList listMock = mock(MyList.class, "myMock");

Posteriormente, defina uma expectativa em um método de simulação e execute-o:

when(listMock.add(anyString())).thenReturn(false);
listMock.add(randomAlphabetic(6));

Criaremos uma verificação com falha intencional que deve gerar uma exceção com a mensagem que contém informações sobre a simulação. Para fazer isso, as expectativas sobre a exceção precisam ser definidas primeiro:

thrown.expect(TooLittleActualInvocations.class);
thrown.expectMessage(containsString("myMock.add"));

A verificação a seguir deve falhar e gerar uma exceção correspondente ao esperado:

verify(listMock, times(2)).add(anyString());

Aqui está a mensagem da exceção lançada:

org.mockito.exceptions.verification.TooLittleActualInvocations:
myMock.add();
Wanted 2 times:
at com.example.mockito.MockitoMockTest
  .whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)
but was 1 time:
at com.example.mockito.MockitoMockTest
  .whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)

Como podemos ver, o nome do mock foi incluído na mensagem de exceção, o que será útil para encontrar o ponto de falha no caso de uma verificação malsucedida.

4. Zombando comAnswer

Aqui, vamos demonstrar o uso de uma variantemock em que a estratégia para as respostas do mock para interação é configurada no momento da criação. A assinatura deste métodomock na documentação do Mockito se parece com o seguinte:

public static  T mock(Class classToMock, Answer defaultAnswer)

Vamos começar com a definição de uma implementação da interfaceAnswer:

class CustomAnswer implements Answer {
    @Override
    public Boolean answer(InvocationOnMock invocation) throws Throwable {
        return false;
    }
}

A classeCustomAnswer acima é usada para a geração de um mock:

MyList listMock = mock(MyList.class, new CustomAnswer());

Se não definirmos uma expectativa sobre um método, a resposta padrão, que foi configurada pelo tipoCustomAnswer, entrará em jogo. Para provar isso, vamos pular a etapa de configuração de expectativa e pular para a execução do método:

boolean added = listMock.add(randomAlphabetic(6));

A seguinte verificação e asserção confirmam que o métodomock com um argumentoAnswer funcionou como esperado:

verify(listMock).add(anyString());
assertThat(added, is(false));

5. Zombando comMockSettings

O método finalmock abordado neste artigo é a variante com um parâmetro do tipoMockSettings. Esse método sobrecarregado é usado para fornecer uma simulação não-padrão.

Existem várias configurações personalizadas que são suportadas por métodos da interfaceMockSettings, como registrar um ouvinte para invocações de método no mock atual cominvocationListeners, configurar a serialização comserializable, especificar a instância para espiar comspiedInstance, configurando o Mockito para tentar usar um construtor ao instanciar um mock comuseConstructor, e alguns outros.

Para sua conveniência, iremos reutilizar a classeCustomAnswer introduzida na seção anterior para criar uma implementaçãoMockSettings que define uma resposta padrão.

Um objetoMockSettings é instanciado por um método de fábrica da seguinte maneira:

MockSettings customSettings = withSettings().defaultAnswer(new CustomAnswer());

Esse objeto de configuração será usado na criação de uma nova simulação:

MyList listMock = mock(MyList.class, customSettings);

Semelhante à seção anterior, vamos invocar o métodoadd de uma instânciaMyList e verificar se um métodomock com um argumentoMockSettings funciona como deve, usando o seguinte snippet de código:

boolean added = listMock.add(randomAlphabetic(6));
verify(listMock).add(anyString());
assertThat(added, is(false));

6. Conclusão

Este tutorial cobriu o métodomock do Mockito em detalhes. A implementação desses exemplos e trechos de código pode ser encontrada ema GitHub project.