A ideia básica do teste unitário é testar uma parte específica do código de cada vez.
Basta pensar assim: "Eu tenho esse pedacinho de código aqui, que está no meio de um monte de outras coisas. Se todas essas outras coisas funcionarem, esse pedacinho também funciona?"
Mas como vc faz pra garantir que todas as outras coisas estão fazendo o que vc quer? Vc poderia testar acessando o sistema, até chegar na situação que quer testar. Só que aí vc estará testando toda a funcionalidade, então não é mais teste unitário.
Como vc só quer testar aquele pedacinho específico e nada mais, então vc simula as outras coisas. Usar mocks é uma das maneiras de fazer isso. Basicamente vc cria um mock pra cada coisa que não está sendo testada, e aí vc faz elas retornarem o que vc precisa.
No seu caso, vc quer testar o EmailValidatorAdapter
. Basicamente, o método isValid
deve retornar exatamente o mesmo valor que o validator
retorna.
Ou seja, quero testar o comportamento do método isValid
: se todo o resto funcionar, isValid
também funciona? E o que é "o resto"? É o validator
.
Eu não quero testar se o validator
funciona (se ele de fato valida corretamente os emails). Isso seria parte de outro teste - por exemplo, um teste unitário só pro validator
, em que vc passa vários emails e verifica se ele valida corretamente.
Não, aqui eu só quero testar o comportamento do EmailValidatorAdapter
, mais especificamente do método isValid
. Se o validator
retorna true
, isValid
também retorna true
? Se o validator
retorna false
, isValid
também retorna false
?
Então o que eu faço? Como o teste só está focando em isValid
, e o validator
faz parte do "resto" (do que não me interessa testar no momento), eu crio um mock do validator
que retorna o que eu preciso em cada caso de teste.
Primeiro eu crio um mock que retorna false
e verifico se isValid
também vai retornar false
. Depois faço o mesmo com true
. E poderia fazer mais casos de teste, se tivessem mais valores possíveis.
Claro que este caso é muito simples, mas tem casos mais complexos em que mocks podem ser bem mais úteis. Por exemplo, se o código precisa acessar algum recurso externo (banco de dados, consultar uma API web, se conectar com outro serviço remoto, etc) e fazer algo com o resultado da consulta. Em vez de acessar estes recursos, vc cria mocks destes, que retornam o que vc precisa. Aí vc consegue testar a parte que manipula o resultado, de maneira isolada e independente (como um teste unitário deve ser).
"Ah, mas e se eu quiser testar o acesso ao recurso externo?"
Aí não é mais teste unitário. Nesse caso, seria mais um teste de integração.