Mocks e Stubs em testes: o que são e quais as diferenças

Mocks e Stubs em testes: o que são e quais as diferenças
Felipe Nascimento
Felipe Nascimento

Compartilhe

Nesse artigo vamos falar sobre mocks e stubs, o que são e quais as suas diferenças.

Para entender esses conceitos, primeiro é importante saber o que são os chamados dublês de teste. Gerard Meszaros, o autor do livro XUnit Test Patterns: Refactoring Test Code usa o termo dublê de teste para qualquer tipo de objeto falso usado no lugar de um objeto real para fins de teste.

Podemos dizer que um dublê nos ajuda testar nosso código eliminando dependências, como por exemplo evitar de fazer uma conexão com banco de dados para testar uma funcionalidade. No livro também ele define os dublês em alguns tipos, nesse artigo vamos focar em mocks e stubs.

Mocks

Ao escrever testes, às vezes precisamos simular partes de nosso sistema para tornar os testes possíveis e os resultados reproduzíveis. Mocks são imitações ou unidades falsas que simulam o comportamento de unidades reais. Por exemplo, temos a seguinte função pagamento() que é responsável por fazer pagamento e dentro dela existe uma outra função que faz conexão com banco de dados, conexão essa que faz parte do processo de pagamento. Essas funções estão dentro de uma classe maior que tem relação com pagamentos:

const pagamento = (descontos, salarioBruto) => { 
 conectaComBanco()

//...código omitido

} 

Para testar a função pagamento() não necessariamente precisamos ter a função conectaComBanco() como dependência, temos que conseguir testar a função pagamento() independente do que acontece dentro da função conectaComBanco().

O que podemos fazer nessa situação é mockar ou criar um mock, simulando assim o comportamento da função conectaComBanco() sem precisar executar de fato a função. Para isso vamos escrever um teste que será feito com a biblioteca sinonjs:

//...código omitido

it(“mock the conectaComBanco function”, function(){
 mock = sinon.mock(ObjetoDeTeste)
 expectation = mock.expects(‘conectaComBanco’)
 expectation.exactly(1)
 ObjetoDeTeste.pagamento(100, 1000)
 mock.verify()
})

O que fizemos nesse teste foi:

Dentro do it descrevemos o teste, depois criamos um mock da classe de pagamento e em seguida dizemos que esse mock espera uma função mock.expects(‘conectaComBanco’). Na variável expectation esperamos que ela seja chamada apenas uma vez. Depois executamos a função pagamento()e verificamos se o teste passou.

Ou seja, com o mock feito, eliminamos dependências complexas que conectaComBanco() precisa executar. Agora que vimos como funciona um mock, vamos para um cenário em que utilizaremos um stub para testar uma unidade.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

Stubs

Os stubs são parecidos com os mocks, mas geralmente são mais simples. Considere a seguinte função de pagamento que recebe uma função chamada salarioFinal() para fazer um cálculo e retornar um salário:

const pagamento = (descontos, salarioBruto) => { 
//...código omitido
 salario = salarioFinal(descontos, salarioBruto)
return salario
} 

Vamos utilizar a biblioteca sinonjs para escrever esse stub:

//...código omitido

it(“stub the aumento function”, function(){
 stub = sinon.stub(ObjetoDeTeste, salarioFinal)
 stub.withArgs(100, 1000).returns(900)
 expect( ObjetoDeTeste.pagamento(10, 1000)).to.be.equal(900)
})

O que fizemos nesse stub foi:

Dentro do it descrevemos o teste, depois criamos um stub da classe de pagamento, passando a função salarioFinal() que retorna um resultado. Em seguida passamos para esse stub os valores que a função salarioFinal() vai receber e o quanto ela deve retornar, por fim testamos a função pagamento, dela é esperado que retorne 900.

O que podemos perceber é que o stub implementa apenas o mínimo para permitir que o código em teste funcione, ou seja, o stub possui um comportamento previsível de retorno, baseado nos parâmetros passados para teste.

Diferenças

Usamos o mock quando queremos saber se uma função vai ser chamada corretamente, quantas vezes ela vai ser chamada, se os parâmetros esperados são os corretos, já o stub vai nos dizer se o resultado do código retorna de acordo com os parâmetros passado, se retorna sucesso, erro ou exceção por exemplo, é previsível.

Para saber mais

Caso queira saber mais sobre os outros tipos de dublês de testes, indico a leitura do artigo clássico do Martin Fowler sobre esse assunto.

Se você gostou desse conteúdo e quer saber mais aqui na Alura temos uma Formação FrontEnd onde vamos mergulhar no oceano do JavaScript.

Felipe Nascimento
Felipe Nascimento

Desenvolvedor e instrutor na Alura com foco em JavaScript.

Veja outros artigos sobre Front-end