Como criar testes unitários no Java utilizando JUnit e Mockito no Spring Boot

Data da publicação: 07/09/2025.

Neste tutorial vou explicar como fazer testes unitários no Java utilizando JUnit, Mockito e Spring Boot

1 Criando um projeto para ser testado

Nesse início, vou considerar que você já possui conhecimento de como iniciar um projeto Maven, porém caso tenha dúvida aconselho a ler meu tutorial da "Minha Primeira API" onde eu explico os passos para fazer isso.

Para aplicar os testes eu criei uma aplicação no meu GitHub, sendo assim você só precisa baixar ela e terá toda a base para aplicar os testes desse tutorial.

Basicamente a aplicação vai ter as seguintes dependências: Actuator para verificar a saúde da aplicação, Web para expor as APIs, Spring Data para ter praticidade em conectar com o banco de dados, H2 que é um banco de dados em memória e Kafka que é para integrar com a mensageria Kafka.

Segue na imagem abaixo as dependências que serão utilizadas nesse tutorial e que você deve adicionar no seu pom.xml.

Print screen da tela do Eclipse exibindo as dependências do arquivo pom.xml

Para fazer os testes unitários foram criadas as classses PessoaController, PessoaService, PessoaRepository, PessoaProducer, PessoaException e Pessoa.

Print screen da tela do Eclipse exibindo a estrutura do projeto

A classe Pessoa é a estrutura do objeto JSON e da tabela do banco de dados. O ideal é que também tivéssemos PessoaDTO para separar a estrutura de JSON e da tabela do banco de dados, mas para fins de estudo vamos usar essa classe para as duas finalidades.

Print screen da tela do Eclipse exibindo a classe Pessoa

A interface PessoaRepository vai ser utilizada para se comunicar com o banco de dados.

Print screen da tela do Eclipse exibindo a interface Pessoa

A classe PessoaException será a exceção lançada para erros tratádos e esperados.

Print screen da tela do Eclipse exibindo a classe PessoaException

A classe PessoaProducer será utilizada para criar enventos para o Kafka de pessoa criada/atualizada e excluída.

Print screen da tela do Eclipse exibindo a classe PessoaProducer

A classe PessoaService vai aplicar algumas regras de negócio.

Print screen da tela do Eclipse exibindo a classe PessoaService 1
Print screen da tela do Eclipse exibindo a classe PessoaService 2

A classe PessoaControler vai ser utilizada para expor as APIS Rest.

Print screen da tela do Eclipse exibindo a classe PessoaController

2 Explicando os 4 pessoas do teste (Contexto, Cenário, Execução e Avaliação)

Para iniciar os testes eu quero que você entenda que todos os testes tem praticamente 4 etapas: a) Entender o contexto que deseja testar, b) Montar o Cenário do teste, c) Executar, d) Avaliar os resultados

a) Entender o contexto que deseja testar significa que você precisa entender o que estará envolvido nesse teste, por exemplo, se você tem um método e esse método recebe um parâmetro e retorna uma String e se chama cadastrar, então aparentemente esse método irá persistir dados no banco de dados e tem um parâmetro que precisará ser criado e o retorno precisará ser testado. Entrando dentro do método você também poderá avaliar quantos cenários você precisará testar, se tiver um if e else já serão dois cenários, se tiver try catch terá mais um cenário para o catch, e assim por diante, porém não é essencial que você entenda tudo antes de começar a testar, primeiro tenha uma visão geral, então crie o primeiro teste para cobrir o cenário principal, aquela que cumprirá a funcionalidade principal, por exemplo, se o método tiver o nome cadastrar, então a funcionalidade principal é cadastrar, depois você terá mais clareza em como fazer o restante dos cenários.

b) Após entender o contexto você precisá Montar o Cenário de teste, que no caso do teste unitário é criar variáveis para enviar como parâmetros para o método, ou então adicionar valores para variáveis que serão utilizadas no meio do teste, ou ainda mockar retornos de métodos de outras classes, ou seja, você deverá garantir que tudo o que for necessário para que o teste aconteça seja fornecido.

c) Com o Cenário montado você precisa executar a funcionalidade, que nada mais é do que executar com os valores criados para a execução do Cenário. Lembre-se que, caso o método que você vá testar retorne algum valor, armazene esse valor em uma variável para testá-lo, ou aplique um teste assim que retornado, isso será visto mais a frente.

d) Agora que a execução foi feita você precisa Avaliar o Resultado. Isso significa que você precisa confirmar que todos os passos esperados pela execução foram executadas, por exemplo, se a expectativa era cadastrar no banco de dados e você está utilizando o Spring Data, garanta que o método do Repository chamado save foi chamado e que o objeto que chegou até ele era o esperado. Avaliar o Resultado é praticamente o passo mais importante do teste, pois com ele você garante que a funcionalidade está agindo conforme esperado e, caso tenha alguma mudança indesejada no código essa avaliação começará a falhar indicando que foi feito algo incorreto ou que o teste precisa se adequar a nova regra de negócio.

3 Testando a classe Producer

Para testar a classe producer, abra a pasta de teste "src/test/java" e dentro do pacote principal dela crie um novo pacote chamado producer. Repare que o ideal é sempre ter a mesma estrutura da classe que será testada. Eu recomendo que você teste uma classe com uma classe de teste, ou seja, o ideal é você não querer testar mais de uma classe em uma classe de teste, então você testará uma classe e irá mockar as outras.

Dentro do pacote de producer criar a class PessoaProducerTest, anote essa classe com "@ExtendWith(MockitoExtension.class)", essa anotação servirá para o JUnit entender que será utilizado o framework Mockito para fazer os testes unitários. Agora crie um atributo privado chamado pessoaProducer do tipo PessoaProducer e anote esse atributo com "@InjetMocks", essa anotação servirá para que o mockito injete mocks dentro do objeto. Os mocks são objetos simulado utilizado pelo Mockito para nós não precisarmos testar classes e métodos fora do nosso escopo de teste. Ainda dentro da classe crie um novo atributo privado dentro da classe chamado objectMapper do tipo ObjectMapper e crie também um outro atributo privado chamado kafkaTemplate do tipo "KafkaTemplate<String, String>", anote cada um desses dois atributos com @Mock, essa anotação servirá para o Mockito criar um objeto mockado (objeto simulado) e adicionar para cada atributo e, como o objeto que queremos testar está anotado como @InjectMocks, então o mockito adicionará esses dois objetos mockados dentro do objeto a ser testado, no nosso caso é o PessoaProducer.

Print screen da tela do Eclipse exibindo a classe de test PessoaProducerTest

Agora vamos criar nosso primeiro teste. Para isso crie um método void chamado "testEnviarCriadaAlterada" que não receberá nenhum parâmetro e anote esse método com "@Test". Como padrão de nomenclatura dos métodos de testes eu costumo usar: "test" + nome_do_método_testado, então nesse caso vamos testar o método "enviarCriadaAlterada" da classe PessoaProducer.

Analisando o método "enviarCriadaAlterada", repare que ele recebe um objeto do tipo pessoa, sendo assim precisaremos criar esse objeto, então na linha 24 ele utiliza o método "writeValueAsString" do objeto "objectMapper" e esse método recebe a mesma pessoa recebida no método e na linha 25 é utilizado o método "send" do objeto "kafkaTemplate" enviando dois parâmetros, um valor fixo de String e outra é a variável "evento", que foi retornado do método "writeValueAsString" do objeto "objectMapper".

Como foi dito precisaremos criar uma pessoa, sendo assim adicione a linha "Pessoa pessoa = new Pessoa();" no seu método de teste. Para a linha do objectMapper, precisaremos mockar (simular) um retorno do método "writeValueAsString" quando ele receber o mesmo objeto pessoa que foi recebido no método "enviarCriadaAlterada". Então dentro do seu teste adicione a linha "String evento = "ESSE SERIA O JSON DA PESSOA";" e outra linha com "Mockito.when (objectMapper .writeValueAsString(pessoa)) .thenReturn(evento);". Repare que seu método começará a dar erro, pois o método "writeValueAsString" lança uma checked exception que obriga a você tratar ou lançar ela, no nosso caso vamos lançar, então adicione o " throws JsonProcessingException" no seu método.

Montado esse cenário podemos executar o método a ser testado, então adicione a linha "pessoaProducer.enviarCriadaAlterada (pessoa);". Repare que esse método é void, sendo assim não conseguimos testar o retorno dele.

Para garantir que a execução foi feita corretamente, adicione uma outra linha após a execução "Mockito.verify(kafkaTemplate, Mockito.times(1)) .send( "pessoa-criada-alterada", evento);", com essa linha nós iremos garantir que os parâmetros esperados chegaram no método "send" do objeto "kafkaTemplate" apenas uma vez, e isso é o que esperamos para a execução do nosso teste.

Print screen da tela do Eclipse exibindo a classe de test PessoaProducerTest com o método testEnviarCriadaAlterada criado

Repare que dentro do método que estamos testando existe um catch para quando o objectMapper não consegue transformar o objeto pessoa em String. Sendo assim também devemos testar esse cenário.

Crie um novo método chamado "testEnviarCriadaAlterada QuandoExisteException" (remova o espaço). Eu adoto esse padrão de nomenclatura de método para quando temos outros cenários fora o principal. Esse método será praticamente igual ao anterior, porém ao invés de mockar o retorno do método "writeValueAsString", nós vamos mockar o lançamento de uma exception. Então você pode copiar e colar o conteúdo do outro método nesse. Substitua a linha de criação do evento por "JsonProcessingException exception = new JsonProcessingException("ERRO AO CONVERTER") {};". Pronto, nesse caso modificamos o cenário para que, quando o método "writeValueAsString" do objeto "objectMapper" for chamado lance uma exception do tipo "JsonProcessingException".

Substitua também a linha onde chamamos a execução do método a ser testado por "PessoaException exceptionRetornada = Assertions.assertThrows(PessoaException.class, () -> pessoaProducer.enviarCriadaAlterada(pessoa));" e adicione uma linha a mais para validar a mensagem com "Assertions.assertEquals("Não foi pessível converter a pessoa em um objeto json no evento de criacao alteracao!", exception.getMessage());", ou seja, agora nós estamos esperando que o método testado "enviarCriadaAlterada" do objeto "pessoaProducer" lance uma exceção do tipo "PessoaException" e que nessa exceção tenha a mensagem "Não foi pessível converter a pessoa em um objeto json no evento de criacao alteracao!".

Por fim substitua a linha onde está verificando a execução do kafkaTemplate por "Mockito.verify( kafkaTemplate, Mockito.times(0)).send(Mockito.anyString(), Mockito.anyString());", pois agora queremos garantir que o método send do kafkaTemplate não seja executado e adicione a anotação "@SuppressWarnings("serial")" no método de teste para evitar o warning.

Print screen da tela do Eclipse exibindo o método testEnviarCriadaAlteradaQuandoExisteException

Agora vamos executar e ver se os dois métodos estão passando. Clique com o botão direito do mouse em cima da classe "PessoaProducerTest" -> Run As -> JUnit Test. Caso eles passem aparecerá um ícone verde abaixo na aba de JUnit.

Print screen da tela do Eclipse exibindo a execução dos dois testes criados

Também é possível avaliar se estamos testando todas as linhas do método utilizando o Coverage. Para isso clique com o botão direito do mouse em cima da classe de teste -> Coverage As -> JUnit Test. Repare que abrirá uma nova aba mostrando a porcentagem de Coverage (Cobertura). Para avaliar a porcentagem ele esta validando todas as classes, sendo assim você precisa abrir apenas a que você esta querendo ver a cobertura, pois ainda não terminamos os testes. Então ao invés de ver a aba de Coverage, abra a classe que você esta testando chamada ""PessoaProducer" e veja que onde testamos ficou verde e o método que falta ser testado ficou vermelho. Sendo assim terminamos um método.

Print screen da tela do Eclipse exibindo a cobertura de testes para classe PessoaProducer

Para testar o método "enviarExcluida" você pode copiar e colar os dois métodos existente de teste e substituir o nome do método de teste, o nome do método testado, o nome do tópico e a mensagem de erro e pronto, você já terá testes para o segundo método. Agora rode novamente o Coverage e veja que todas as linhas dos métodos ficaram verdes, então finalizamos os testes para a classe PessoaController.

Print screen da tela do Eclipse exibindo testes para pessoa excluída
Print screen da tela do Eclipse exibindo a cobertura de testes para classe PessoaProducer

4 Testando a classe Controller

Agora que já fizemos os testes para a primeira classe, podemos utilizar basicamente tudo o que foi utilizado lá para aplicar nessa classe de controller. Crie o pacote "controller" dentro do pacote raiz dos testes. Então crie a classe "PessoaControllerTest" dentro desse pacote.

Crie o atributo privado pessoaController do tipo PessoaController e anote ele com "@InjectMocks". Agora crie outro atributo privado chamado pessoaService do tipo PessoaService e anote ele com "@Mock".

Já temos o objeto da classe que vai ser testada e o objeto mockado da classe que não vai ser testada. Crie um método void chamado "testCadastrar" que não receberá nenhum parâmetro. Dentro desse método crie um objeto de pessoa na primeira linha, na segunda linha crie uma outra pessoa, na terceira linha Mock a resposta do método cadastrar do objeto pessoaService para quando receber a pessoa da primeira linha retorne a pessoa da segunda linha. Na quarta linha receba o retorno da execução do método cadastrar do objeto pessoaController passando o objeto pessoa da primeira linha. Na quinta e última linha vamos utilizar o Assertions.assertEquals para comparar se o objeto retornado na quarta linha é igual à pessoa criada na segunda linha e com isso terminamos o teste do cadastrar.

Print screen da tela do Eclipse exibindo a classe PessoaControllerTest
Print screen da tela do Eclipse exibindo a cobertura de testes para classe PessoaController

Agora basicamente o método de teste precisa ser copiado e colado para cada método diferente a ser testado mudando variáveis quando for necessário e métodos chamados. Deixarei os outrs testes como exercício.

5 Testando a classe Service

A classe de Service é a mais trabalhosa, pois ela possui várias regras. Vamos fazer o método alterar, pois ele é o mais complexo. Veja que existe um if com várias condições, no lado do teste cada condição será um cenário diferente, sendo assim teremos um total de 6 cenários, um para cada condição do IF e um para quando não entrar em nenhum condição do IF.

Começe criando o pacote service dentro do pacote principal da pasta de testes. Agora crie a classe PessoaService e anote ela com "@ExtendWith(MockitoExtension.class)". Crie o atributo privado "pessoaService" do tipo "PessoaService" e anote ele com "@InjectMocks". Agora crie dois atributos privados, um chamado "pessoaRepository" do tipo "PessoaRepository" e outro chamado "pessoaProducer" do tipo "PessoaProducer", anote cada um com "@Mock". Pronto a classe para nossos testes está pronta.

Print screen da tela do Eclipse exibindo a classe PessoaServiceTest com a estrutura básica

a) O primeiro cenário é quando o método recebe o objeto pessoa como nulo, então ele deve lançar a exceção PessoaException. Podemos fazer esse teste com apenas uma linha de código sendo "Assertions.assertThrows(PessoaException.class, () -> pessoaService.alterar(null));", então crie um método void chamado "testAlterarQuandoPessoaNula", anote esse método com "@Test" e adicione a linha mencionada dentro dele.

Print screen da tela do Eclipse exibindo a classe PessoaServiceTest com o primeiro teste de alterar

b) O segundo cenário é quando o método recebe o objeto pessoa e na pessoa existe um id igual a nulo, então ele deve lançar a exceção PessoaException. Crie um método void chamado "testAlterarQuandoPessoaIdNulo". Dentro do método crie um objeto chamado "pessoa" do tipo "Pessoa" e na próxima linha adicione "Assertions.assertThrows(PessoaException.class, () -> pessoaService.alterar(pessoa));" e pronto, com isso já testamos que quando o id for nulo será lançada a exceção PessoaException.

c) O terceiro cenário é quando o método recebe o objeto pessoa e na pessoa existe um nome igual a nulo, então ele deve lançar a exceção PessoaException. Crie um método void chamado "testAlterarQuandoPessoaNomeNulo". Dentro do método crie um objeto chamado "pessoa" do tipo "Pessoa", na próxima linha adicione um id para essa pessoa "pessoa.setId(1L);" e na linha seguinte adicione "Assertions.assertThrows(PessoaException.class, () -> pessoaService.alterar(pessoa));" e pronto.

d) O quarto cenário é quando o método recebe o objeto pessoa e na pessoa existe um nome for vazio, então ele deve lançar a exceção PessoaException. Crie um método void chamado "testAlterarQuandoPessoaNomeVazio". Dentro do método crie um objeto chamado "pessoa" do tipo "Pessoa", na próxima linha adicione um id para essa pessoa "pessoa.setId(1L);", na outra adicione um nome vazio "pessoa.setNome(" ");", e na linha seguinte adicione "Assertions.assertThrows(PessoaException.class, () -> pessoaService.alterar(pessoa));" e pronto.

e) O quinto cenário é quando o método recebe o objeto pessoa e a pessoa não foi encontrada no banco de dados, então ele deve lançar a exceção PessoaException. Crie um método void chamado "testAlterarQuandoPessoaNaoExiste". Dentro do método crie um objeto chamado "pessoa" do tipo "Pessoa", na próxima linha adicione um id para essa pessoa "pessoa.setId(1L);", na outra adicione um nome vazio "pessoa.setNome("NOME");", na próxima "Mockito.when(pessoaRepository.existsById(pessoa.getId())) .thenReturn(false);",e na linha seguinte adicione "Assertions.assertThrows(PessoaException.class, () -> pessoaService.alterar(pessoa));" e pronto.

Print screen da tela do Eclipse exibindo a classe PessoaServiceTest com o quatro testes de alterar

f) O sexto e último cenário do método alterar é quando a pessoa efetivamente será alterada. Sendo assim crie um método void chamado "testAlterar". Na primeira linha desse método crie a pessoa "Pessoa pessoa = new Pessoa();", na segunda linha coloque o id "pessoa.setId(1L);", na terceira linha coloque no nome "pessoa.setNome("Alterando");", na quarta linha crie a simulação do retorno do método do objeto pessoaRepository como true "Mockito.when(pessoaRepository.existsById(pessoa.getId())) .thenReturn(true);", na quinta linha crie o objeto pessoaAlterada do tipo Pessoa "Pessoa pessoaAlterada = new Pessoa();", na sexta linha simule o retorno do pessoaRepository método save recebendo pessoa para retornar pessoaAlterada "Mockito.when( pessoaRepository.save(pessoa)) .thenReturn(pessoaAlterada);", na sétima linha receba o retorno do método alterar do objeto pessoaService passando o primeiro objeto de pessoa criado "Pessoa pessoaRetornada = pessoaService.alterar(pessoa);", na oitava linha compare se a pessoaRetornada é igual a pessoaAlterada "Assertions.assertEquals(pessoaAlterada, pessoaRetornada);" e na última linha verifique se a pessoaAlterada passou pelo método "enviarCriadaAlterada" do objeto "pessoaProducer" com "Mockito.verify(pessoaProducer, Mockito.times(1)) .enviarCriadaAlterada(pessoaAlterada);" e pronto, o teste esta feito.

Print screen da tela do Eclipse exibindo a classe PessoaServiceTest com o quatro testes de alterar

Agora execute o Coverage (botão direito do Mouse na classe PessoaServiceTest -> Coverage As -> JUnit Test), abra a classe PessoaService e veja que o método alterar ficou completamente verde.

Print screen da tela do Eclipse exibindo a cobertura de testes da classe PessoaService

Repare que os outros método ficaram vermelhos, então vou deixar de exercício que você aplique os testes utilizando o que foi aprendido no método alterar nos outros métodos.

Conclusão

Após fazer esse tutorial você conseguiu aplicar testes unitários para cenários diversos, como por exemplo métodos que retornam valores e métodos que não retornam valores. Também viu alguns conceitos de testes e como Mockar (simular) objetos e retornos de métodos. PARABÉNSSS por ter chegado até aqui!!! E eu aconselho que você faça os exercícios deixado para consolidar o seu conhecimento.

Assista também os vídeos no youtube