DEV Community

Giovani
Giovani

Posted on

Mockito

LINK PARA ARTIGO ORIGINAL - ARTIGO ORIGINAL

Os testes de unidade são fundamentais no desenvolvimento de software. Eles consistem em testar pequenas partes isoladas do código para garantir seu funcionamento correto. O Mockito é uma biblioteca popular em Java para a criação de testes de unidade, permitindo que os desenvolvedores criem objetos simulados que imitam o comportamento de objetos reais em seus testes. Neste post, vamos explorar como utilizar o Mockito para escrever testes de unidade em código Java.

O que é o_ Mockito_?

Mockito é uma biblioteca open-source em Java que permite criar objetos simulados para testar unidades de código de forma isolada. Ela oferece recursos para simular comportamentos, verificar chamadas de métodos e realizar testes no estilo BDD. Amplamente utilizada em aplicações Java, pode ser facilmente integrada com frameworks de teste como JUnit e TestNG.

Configurando o Mockito

Para usar o Mockito em um projeto Java, você precisa adicionar a biblioteca Mockito como uma dependência. A versão mais recente do Mockito pode ser baixada do site oficial . Você também pode adicionar o Mockito como uma dependência em seu projeto adicionando as seguintes linhas ao seu pom.xml arquivo:

<dependência> 
  <groupId>org.mockito</groupId> 
  <artifactId>mockito-core</artifactId> 
  <versão>3.12.4</versão> 
  <escopo>teste</escopo> 
</dependência>
Enter fullscreen mode Exit fullscreen mode

Depois de adicionar a dependência do Mockito, você pode começar a usá-la em seus testes de unidade.

Criando um objeto simulado

O primeiro passo para usar o Mockito é criar um objeto mock. Um objeto mock é um objeto simulado que pode ser usado no lugar de um objeto real em um teste de unidade. Para criar um objeto mock no Mockito, você pode usar o método Mockito.mock() . Este método pega um objeto Class como argumento e retorna um objeto mock dessa classe.

import static org.mockito.Mockito.mock; 

public class ExampleTest { 
  @Test 
  public void test() { 
    // Cria um objeto simulado da classe Example 
    Example example = mock(Example.class); 
    // Usa o objeto simulado no teste 
  } 
}
Enter fullscreen mode Exit fullscreen mode

No código acima, criamos um objeto simulado da Exampleclasse usando o mock()método.

Métodos de stubbing

O próximo passo no uso do Mockito é fazer stub de métodos no objeto mock. Stubs são usados ​​para definir o comportamento de métodos em um objeto mock. No Mockito, você pode fazer stub de métodos usando o método Mockito.when(). Este método recebe uma chamada de método como argumento e retorna um objeto Mockito.stub() , que pode ser usado para definir o comportamento do método.

import static org.mockito.Mockito.when; 

public class ExampleTest { 
  @Test 
  public void test() { 
    // Crie um objeto simulado da classe Example 
    Example example = mock(Example.class); 
    // Stub do método doSomething() para retornar "Hello" 
    when(example.doSomething()).thenReturn("Hello"); 
    // Use o objeto simulado no teste 
    assertEquals("Hello", example.doSomething()); 
  } 
}
Enter fullscreen mode Exit fullscreen mode

No código acima, criamos um objeto mock da Exampleclasse e fazemos um stub do doSomething()método para retornar a string "Hello". Em seguida, usamos o objeto mock no teste e verificamos se o método retorna o valor esperado.

Verificando chamadas de método

Outro recurso importante do Mockito é a capacidade de verificar chamadas de método em um objeto mock. Isso permite que você garanta que um método foi chamado com os argumentos corretos e o número correto de vezes.

import static org.mockito.Mockito.*; 

public class ExampleTest { 

    @Test 
    public void testMethodCallVerification() { 
        // cria objeto simulado 
        List<String> mockedList = mock(List.class); 

        // chama métodos no objeto simulado 
        mockedList.add("a"); 
        mockedList.add("b"); 
        mockedList.add("c"); 
        mockedList.add("c"); 

        // verifica se o método 'add' foi chamado com os argumentos corretos 
        verify(mockedList).add("a"); 
        verify(mockedList).add("b"); 
        verify(mockedList, times(2)).add("c"); 

        // verifica se o método 'add' foi chamado 4 vezes no total 
        verify(mockedList, times(4)).add(anyString()); 

        // verifica se o método 'clear' não foi chamado 
        verify(mockedList, never()).clear(); 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, criamos um objeto mock da Listclasse usando o método mock(). Então, chamamos o método add() no objeto mock com vários argumentos.

Em seguida, usamos o método verify() para verificar se o método add() foi chamado com os argumentos corretos e o número correto de vezes. Usamos o times()método para especificar o número de vezes que um método deveria ter sido chamado.

Por fim, usamos o never()método para verificar se o clear()método nunca foi chamado no objeto simulado.

Ao usar essas técnicas de verificação, podemos garantir que nosso código está chamando métodos em nossos objetos simulados corretamente e que nossos testes de unidade estão testando o comportamento desejado.

Verifique o comportamento

Após configurar os objetos mock e chamar o método, é importante verificar se o comportamento esperado ocorreu. O Mockito fornece uma variedade de métodos para fazer isso, como verify() e verifyNoMoreInteractions(). Esses métodos podem ser usados ​​para verificar se um método foi chamado um certo número de vezes, ou se nenhuma outra interação com o objeto mock ocorreu após um certo ponto.

import static org.mockito.Mockito.*;

public class ExampleTest { 

    @Test 
    public void testMethodBehavior() { 
        // criar objeto fictício 
        List<String> mockedList = mock(List.class); 

        // chamar método no objeto fictício 
        mockedList.add("a"); 

        // verificar se o comportamento do método é o esperado 
        verify(mockedList).add("a"); 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, criamos um objeto mock da Listclasse usando o método mock() . Então chamamos o método add() no objeto mock com o argumento "a".

Usamos o método verify() para verificar se o método add() foi chamado no objeto mock com o argumento "a". Se o método não foi chamado, ou se foi chamado com um argumento diferente, o teste falharia.

Este exemplo demonstra um caso simples em que chamamos o método apenas uma vez com um argumento, mas podemos usar os métodos de verificação do Mockito para verificar comportamentos mais complexos também. Podemos especificar o número de vezes que um método deveria ter sido chamado, verificar se um método não foi chamado e muito mais. Isso nos permite garantir que nosso código esteja se comportando conforme o esperado e que nossos testes unitários estejam efetivamente testando o comportamento desejado.

CleanUp

Após cada teste, é importante limpar quaisquer recursos que foram usados. Isso inclui redefinir quaisquer objetos simulados ou dublês de teste que foram criados. O Mockito fornece uma anotação @After conveniente que pode ser usada para especificar métodos que devem ser chamados após cada teste.

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.*;

public class ExampleTest { 

    @Mock 
    private ExampleService exampleService; 

    @Before 
    public void setUp() { 
        MockitoAnnotations.initMocks(this); 
    } 

    @After 
    public void tearDown() { 
        reset(exampleService); 
    } 

    @Test 
    public void testExampleMethod() { 
        // configurar comportamento simulado 
        when(exampleService.exampleMethod()).thenReturn("Olá, Mundo!"); 

        // chamar método usando objeto simulado 
        String result = exampleService.exampleMethod(); 

        // verificar se o comportamento simulado foi chamado 
        verify(exampleService).exampleMethod(); 

        // verificar resultado 
        assertEquals("Olá, Mundo!", result); 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, criamos um objeto mock da classe ExampleService usando a anotação @Mock. Em seguida, usamos a anotação @Before para inicializar o objeto mock usando MockitoAnnotations.initMocks(this).

Usamos a anotação @After para especificar um método que deve ser chamado após cada teste. Neste caso, usamos o método reset() para redefinir o objeto exampleService mock para seu estado inicial.

No método testExampleMethod() de teste, configuramos o comportamento simulado usando o método when(), chamamos um método no objeto simulado e verificamos se o comportamento simulado foi chamado usando o método verify(). Finalmente, verificamos o resultado da chamada do método usando uma asserção.

Ao usar a anotação @After e o método reset(), garantimos que o objeto exampleService simulado seja redefinido para seu estado inicial após cada teste, permitindo-nos escrever testes unitários independentes e confiáveis.

Exemplo

Aqui está um exemplo de um teste de unidade usando o Mockito:

@Test 
public void testGetUserById() { 
   // Simula a dependência UserDao 
   UserDao userDao = Mockito.mock(UserDao.class); 

   // Cria um objeto de usuário de exemplo 
   User expectedUser = new User(); 
   expectedUser.setId(123); 
   expectedUser.setUsername("testUser"); 
   expectedUser.setEmail("testUser@example.com"); 

   // Define o comportamento do objeto simulado UserDao 
   Mockito.when(userDao.getUserById(123)).thenReturn(expectedUser); 

   // Chama o método em teste 
   UserService userService = new UserService(userDao); 
   User actualUser = userService.getUserById(123); 

   // Verifica se o método UserDao foi chamado 
   Mockito.verify(userDao).getUserById(123); 

   // Verifica se o método retornou o resultado esperado 
   assertEquals(expectedUser, actualUser); 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos testando uma classe UserService que tem uma dependência de uma classe UserDao. Estamos usando o Mockito para criar um objeto UserDao simulado e definindo seu comportamento usando o método when(). Estamos então chamando o método em teste e verificando se o método getUserById() foi chamado no objeto simulado usando o método verify(). Finalmente, estamos usando o método assertEquals() para verificar se o método em teste retornou o resultado esperado.

Seguindo essas etapas, podemos escrever testes unitários abrangentes e confiáveis ​​que verificam o comportamento do nosso código. O Mockito é uma ferramenta poderosa que facilita a criação de objetos simulados e a definição de seu comportamento, o que pode nos ajudar a escrever melhores testes e identificar problemas logo no início do processo de desenvolvimento.

Correspondentes de parâmetros:

O Mockito fornece um recurso para usar matchers de parâmetros como eq(), any(), etc. que são usados ​​para definir o comportamento esperado de objetos mock com mais flexibilidade. Ajuda a evitar a codificação rígida dos valores de parâmetros, o que pode ser trabalhoso ao testar métodos complexos.

Tratamento de exceções:

Quando um método em teste lança uma exceção, é importante testar se a exceção foi tratada corretamente. O Mockito fornece uma maneira de testar isso usando o método doThrow() para lançar uma exceção de um objeto simulado e o método assertThrows() para verificar se a exceção foi lançada e tratada corretamente.

Zombaria parcial:

O Mockito também fornece um recurso para criar objetos mock parciais, o que nos permite testar métodos específicos de um objeto enquanto ainda usamos a implementação real para outros métodos. Isso pode ser útil ao testar métodos que têm interações complexas com outras partes do código.

Aqui está um exemplo de uso de correspondentes de parâmetros e tratamento de exceções em um teste de unidade:

@Test 
public void testDivideByZero() { 
   Calculator calculator = Mockito.mock(Calculator.class); 

   // Defina o comportamento do método divide() 
   Mockito.when(calculator.divide(Mockito.anyInt(), Mockito.eq(0))) 
          .thenThrow(new ArithmeticException("Divisão por zero")); 

   // Chame o método em teste 
   int result = calculator.divide(10, 0); 

   // Verifique se o método lançou uma exceção 
   assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0)); 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos testando uma classe Calculator que tem um método divide(). Estamos usando matchers de parâmetros para definir o comportamento do objeto mock, e o método thenThrow() para lançar uma exceção quando o segundo parâmetro for zero. Estamos então chamando o método em teste, e verificando se ele lançou um ArithmeticException quando chamado com 10 e 0.

Ao seguir essas práticas recomendadas para escrever testes unitários usando o Mockito, podemos criar testes robustos e confiáveis ​​que nos ajudam a identificar e corrigir problemas logo no início do processo de desenvolvimento. Ao aproveitar o poder dos objetos simulados e dos correspondentes de parâmetros, podemos testar interações complexas entre objetos e verificar se nosso código se comporta corretamente em todos os cenários.

Aqui estão mais algumas técnicas que você pode usar com o Mockito para melhorar seus testes de unidade:

Verificando métodos privados: O Mockito fornece uma maneira de testar métodos privados de uma classe usando a biblioteca PowerMockito. Esta biblioteca estende a funcionalidade do Mockito para dar suporte a testes de métodos privados, métodos estáticos e outros tipos de comportamento que podem ser desafiadores para testar usando técnicas tradicionais de mocking. Para usar PowerMockito, você precisará incluí-lo como uma dependência em seu projeto e anotar sua classe de teste com @RunWith(PowerMockRunner.class).

Aqui está um exemplo de uso PowerMockito para testar um método privado:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(MyClass.class) 
public class MyClassTest { 

   @Test 
   public void testPrivateMethod() throws Exception { 
      MyClass myClass = new MyClass(); 

      PowerMockito.spy(myClass); 
      PowerMockito.doReturn("mockedValue").when(myClass, "privateMethod"); 

      String result = myClass.publicMethod(); 

      assertEquals("mockedValue", result); 
   } 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos testando um método público publicMethod() de uma MyClassclasse que chama um método privado privateMethod(). Estamos usando PowerMockito.spy() para criar um objeto espião de MyClasse PowerMockito.doReturn() para simular o valor de retorno do método privado privateMethod(). Estamos então chamando publicMethod() e verificando se ele retorna o valor simulado.

Métodos estáticos de mocking: O Mockito também fornece uma maneira de mockar métodos estáticos de uma classe usando a biblioteca PowerMockito . Isso pode ser útil quando você precisa mockar um método estático em uma biblioteca de terceiros ou uma base de código legada.

Aqui está um exemplo de uso PowerMockito para simular um método estático:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(MyClass.class) 
public class MyClassTest { 

   @Test 
   public void testStaticMethod() { 
      PowerMockito.mockStatic(MyClass.class); 
      Mockito.when(MyClass.staticMethod(Mockito.anyString())) 
             .thenReturn("mockedValue"); 

      String result = MyClass.staticMethod("input"); 

      assertEquals("mockedValue", result); 
   } 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos usando PowerMockito.mockStatic() para simular o método estático staticMethod()de uma MyClassclasse e Mockito.when() para definir o comportamento do método simulado. Estamos então chamando o método estático e verificando se ele retorna o valor simulado.

Construtores de Mocking: O Mockito também fornece uma maneira de mockar construtores de uma classe usando a biblioteca Mockito . Isso pode ser útil quando você precisa testar uma classe que tem dependências complexas.

Aqui está um exemplo de uso Mockito para simular um construtor:

@Test
public void testConstructor() {
   MyDependency myDependencyMock = Mockito.mock(MyDependency.class);
   Mockito.when(myDependencyMock.getDependencyValue())
          .thenReturn("mockedValue");

   MyClass myClass = new MyClass(myDependencyMock);

   assertEquals("mockedValue", myClass.getDependencyValue());
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, estamos testando uma classe MyClass que tem uma dependência em uma classe MyDependency. Estamos usando Mockito.mock() para criar um objeto mock de MyDependencye Mockito.when() para definir o comportamento do método getDependencyValue(). Estamos então criando uma instância de MyClasspassando a dependência mockada e verificando se ela retorna o valor mockado.

Captores de Argumentos: Os captores de argumentos são usados ​​para capturar os argumentos passados ​​para uma chamada de método. Isso é útil quando você quer verificar o estado dos argumentos que foram passados ​​para um método. Aqui está um exemplo:

@Test
public void testAddUser() {
    UserRepository userRepository = Mockito.spy(new UserRepository());
    UserService userService = new UserService(userRepository);
    userService.addUser(new User("John", "Doe"));
    Mockito.verify(userRepository).save(Mockito.any(User.class));
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, um captor de argumento é usado para capturar o objeto User que é passado para o método userRepository.save(). Os valores do objeto User capturado são então verificados para garantir que os dados corretos foram passados ​​para o método.

Objetos Spy: Objetos Spy são usados ​​para zombar parcialmente de um objeto. Isso é útil quando você quer testar um método que depende do comportamento de um objeto, mas não quer zombar de todos os métodos do objeto. Aqui está um exemplo:

@Test 
public void testAddUser() { 
    UserRepository userRepository = Mockito.spy(new UserRepository()); 
    UserService userService = new UserService(userRepository); 
    userService.addUser(new User("John", "Doe")); 
    Mockito.verify(userRepository).save(Mockito.any(User.class)); 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, um objeto espião é criado para a UserRepositoryclasse. O método addUser() da classe UserService é então chamado com um objeto User. O método userRepository.save() é então verificado para garantir que ele foi chamado com qualquer objeto User.

Métodos estáticos de mocking: Mockito também pode ser usado para mockar métodos estáticos. Isso é útil quando você precisa mockar um método que é chamado estaticamente e não pode ser substituído. Aqui está um exemplo:

@Test 
public void testAddUser() { 
    PowerMockito.mockStatic(UserUtils.class); 
    Mockito.when(UserUtils.generateUserName(Mockito.anyString())).thenReturn("johndoe"); 
    String userName = UserUtils.generateUserName("John Doe"); 
    assertEquals("johndoe", userName); 
    PowerMockito.verifyStatic(UserUtils.class); 
    UserUtils.generateUserName(Mockito.anyString()); 
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, o método UserUtils.generateUserName() é simulado usando o método PowerMockito.mockStatic(). O comportamento do método é então definido usando o método Mockito.when(). O método é então chamado com um valor e o valor retornado é verificado usando o método assertEquals(). Finalmente, o método PowerMockito.verifyStatic() é usado para verificar se o método foi chamado com os argumentos corretos.

Esses são apenas alguns exemplos das muitas técnicas que você pode usar com o Mockito para escrever testes unitários eficazes. Ao usar essas técnicas, você pode escrever testes que são mais confiáveis, mais fáceis de manter e melhores em capturar bugs no início do processo de desenvolvimento.

Concluindo, o Mockito é uma ferramenta poderosa e fácil de usar que pode ajudar os desenvolvedores a escrever testes unitários eficazes para seus códigos. Ao alavancar as técnicas discutidas neste blog, você pode criar casos de teste robustos que ajudarão você a detectar bugs no início do ciclo de desenvolvimento e garantir a qualidade do seu código.

Lembre-se, testes eficazes são uma parte essencial do processo de desenvolvimento de software, e o Mockito pode ajudar você a simplificar esse processo e torná-lo mais eficiente. Então, comece a explorar os recursos do Mockito hoje mesmo e leve seu jogo de testes unitários para o próximo nível!

Top comments (0)