DEV Community

João Victor Martins
João Victor Martins

Posted on

[PR-BR] Testes de unidade com MockK e AssertJ

Sempre que estamos falando sobre boas práticas de desenvolvimento de software, um nome sempre aparece: testes de unidade. De acordo com Marco Tulio Valente (2020), testes de unidade são testes automatizados de pequenas unidades de código, normalmente classes, as quais são testadas de forma isolada do restante do sistema. Um teste de unidade é um programa que chama métodos de uma classe e verifica se eles retornam os resultados esperados. Esses testes podem ser feitos na maioria das linguagens de programação e cada uma delas possui bibliotecas e recursos para facilitar o desenvolvimento dos mesmos. A ideia do post é mostrar como fazer testes de unidade em kotlin usando mockK e AssertJ.

MockK

Mockk é uma biblioteca de mocking para kotlin que traz uma série de recursos como Spy, Relaxed mock, Partial mocking, Object mocks, Class mock entre outros.

AssertJ

O AssertJ fornece um rico conjunto de asserções, mensagens de erro realmente úteis, melhora a legibilidade do código de teste e foi projetado para ser super fácil de usar em sua IDE favorita.

Dependências

Para criar testes de unidade com as bibliotecas informadas, é necessário adicionar as dependências no projeto. No caso do maven basta colocar o trecho a seguir no pom.xml (verificar versões)

        <dependency>
            <groupId>io.mockk</groupId>
            <artifactId>mockk</artifactId>
            <version>1.12.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.21.0</version>
            <scope>test</scope>
        </dependency>
Enter fullscreen mode Exit fullscreen mode

Mãos na massa

Suponha que é necessário testar o comportamento de um método que lista produtos. O método possui dois fluxos. Quando é informado o nome do produto a ser listado, deve-se retornar apenas o produto especificado. Quando o nome do produto não é informado, deve-se retornar todos os produtos.

// Resto do código omitido

fun listar(nomeProduto: String?): List<Produto> {
        return nomeProduto?.let {
            repository.findByProdutoNome(nomeProduto)
        } ?: repository.findAll()
    }
Enter fullscreen mode Exit fullscreen mode

O primeiro teste será para validar o comportamento do método quando é informado o nome do produto.

import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.assertj.core.api.Assertions.*
// Outros imports foram omitidos

class ProdutoServiceTest {

        private val repository: ProdutoRepository = mockk()
        private val produtoService = ProdutoService(repository)

        @Test
        fun `deve listar produto por nome`() {
                every { repository.findByProdutoNome(any()) } returns listOf(Produto("Geladeira"))

                val result = produtoService.listar(any())

                verify(exactly = 0) { produtoRepository.findAll() }
                verify(exactly = 1) { produtoRepository.findByProdutoNome(any()) }

                assertThat(resultado).isNotNull
                assertThat(resultado).hasSize(1)
        }
}
Enter fullscreen mode Exit fullscreen mode

Vamos entender alguns recursos apresentados. Como a ideia do teste de unidade é testar apenas o comportamento do método que contém a regra de negócio, toda a parte de repositório deverá ser mockada. Para mockar objetos com o mockK pode-se utilizar a inline function mockk(). Há duas formas de utilizá-la, da forma que foi declarada acima ou com mockk<ProdutoRepository>(). Com o repositório mockado, é necessário definir o seu comportamento. Para isto é criado o bloco every que descreve qual resposta deve ser dada quando um método do repositório for chamado. No caso acima, sempre que o método findByProdutoNome for chamado, será retornado uma lista de produtos que possui apenas um produto. O verify será o bloco responsável por verificar se o mock foi invocado como esperado. Como o método possui dois fluxos, temos que garantir que quando for informado o nome do produto, o método do repositório findAll() não seja chamado e sim o findByProdutoNome(). Qualquer comportamento diferente deste deverá fazer o teste falhar. Tudo que foi falado até aqui são recursos do mockk e já seria suficiente para fazer o teste ser executado com sucesso. Porém para garantir que o resultado retornado está correto, podemos fazer asserções e é neste momento que o AssertJ vira protagonista. Para escrever uma asserção, você sempre precisa começar passando seu objeto para o método assertThat() e então seguir com as asserções reais. No caso acima, estamos afirmando que o resultado não é nulo e a lista possui um elemento. Qualquer retorno diferente disso, significaria que o método listar de ProdutoService não está de acordo com o comportamento esperado, e mais uma vez o teste deverá falhar. Agora que entendemos todos os recursos utilizados no teste, podemos testar o outro fluxo, quando não é informado o nome do produto.

import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.assertj.core.api.Assertions.*
// Outros imports foram omitidos

class ProdutoServiceTest {

        private val repository: ProdutoRepository = mockk()
        private val produtoService = ProdutoService(repository)

        @Test
        fun `deve listar todos os produtos`() {
                every { repository.findAll() } returns listOf(Produto("Geladeira"), Produto("Televisao"))

                val result = produtoService.listar()

                verify(exactly = 1) { produtoRepository.findAll() }
                verify(exactly = 0) { produtoRepository.findByProdutoNome(any()) }

                assertThat(resultado).isNotNull
                assertThat(resultado).hasSize(2)
        }

Enter fullscreen mode Exit fullscreen mode

Conclusão

Podemos ver que ambas as bibliotecas nos fornecem recursos poderosos para criar testes de unidades simples, elegantes e eficientes. Existem muitos outros recursos a serem explorados, o que não caberia em apenas um post. Para quem tiver interesse em continuar os estudos, abaixo, em referências, deixei alguns links que vão auxiliar. Espero que tenham gostado da leitura e qualquer dúvida, crítica ou sugestão, não deixem de comentar. Até a próxima!!

Referências
https://mockk.io/
https://joel-costigliola.github.io/assertj/
https://www.baeldung.com/kotlin/mockk
https://www.baeldung.com/introduction-to-assertj

Bibliografia
Marco Tulio Valente. Engenharia de Software Moderna: Princípios e Práticas para Desenvolvimento de Software com Produtividade, 2020.

Discussion (3)

Collapse
cpdaniiel profile image
Daniel Cavalcanti

Thanks

Collapse
paulo_iggor profile image
Paulo Igor

Wow!!!

Collapse
freeluke_ profile image
Lukas Henrique

Sempre bom ler mais sobre o Mockk! Parabéns