Introdução: por que métodos void são uma dor de cabeça para iniciantes?
\n\nVocê já escreveu um teste unitário em Java com Mockito e de repente bateu numa parede? Até parece simples: você mocka um objeto, configura o comportamento para métodos que retornam algo (string, número, lista). Mas quando chega a vez dos métodos void — aqueles que não retornam nada, apenas fazem algo internamente (como salvar dados, enviar e-mail, registrar uma ação) — começa o bloqueio.
\n\nPor quê? Porque o habitual when(mock.someMethod()).thenReturn(something) não funciona aqui. O compilador simplesmente não permite escrever when(mock.voidMethod()).thenReturn(...) — o método void não retorna nada, e thenReturn não faz sentido.
É exatamente essa pergunta — "How to mock void methods with Mockito" — que acumulou milhares de visualizações no Stack Overflow. E hoje vamos resolvê-la de uma vez por todas. Você aprenderá não apenas a mockar métodos void, mas a fazer isso de forma correta, elegante e sem sofrimento.
\n\nVamos nessa! 🚀
\n\nO que é um método void do ponto de vista de teste?
\n\nUm método void é um método que executa uma ação, mas não retorna um resultado. Por exemplo:
\n\npublic class EmailService {\n public void sendWelcomeEmail(String email) {\n // aqui o envio real do e-mail\n System.out.println("Enviando e-mail para " + email);\n }\n}\n\nEm um projeto real, não queremos que, a cada execução do teste, um e-mail seja realmente enviado. Precisamos apenas verificar se o método foi chamado, ou silenciar sua execução, ou fazê-lo lançar uma exceção (para testar o tratamento de erros).
\n\nPara isso, o Mockito fornece uma sintaxe especial usando doNothing(), doThrow(), doAnswer() e doCallRealMethod().
1. O caso mais comum: doNothing() — apenas silenciar o método void
\n\nSe você precisa que o método void não faça nada quando for chamado — use doNothing(). Este é o comportamento padrão do Mockito para métodos void, mas às vezes é útil especificá-lo explicitamente (por exemplo, para legibilidade ou ao usar spy).
import org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.*;\n\n@ExtendWith(MockitoExtension.class)\npublic class EmailServiceTest {\n\n @Mock\n private EmailService emailService;\n\n @Test\n void testDoNothing() {\n // Configura: ao chamar sendWelcomeEmail, não fazer nada\n doNothing().when(emailService).sendWelcomeEmail(anyString());\n\n // Chama o método\n emailService.sendWelcomeEmail("test@example.com");\n\n // Verifica se o método foi realmente chamado\n verify(emailService).sendWelcomeEmail("test@example.com");\n }\n}\n\nImportante: Se você estiver usando @Mock, não precisa escrever doNothing() — o Mockito por padrão torna os métodos void "vazios". Mas se estiver usando @Spy (espião), o método real será chamado, e doNothing() é necessário para evitar isso.
2. doThrow() — simulando um erro em um método void
\n\nUma tarefa muito comum: verificar como seu código reage se o serviço de envio de e-mails falhar com um erro. Para isso, fazemos o método void lançar uma exceção.
\n\n@Test\nvoid testDoThrow() {\n // Configura: ao chamar sendWelcomeEmail, lançar RuntimeException\n doThrow(new RuntimeException("Erro ao enviar e-mail"))\n .when(emailService).sendWelcomeEmail(anyString());\n\n // Agora, ao chamar o método, uma exceção será lançada\n assertThrows(RuntimeException.class, () -> {\n emailService.sendWelcomeEmail("fail@example.com");\n });\n\n