Teste de unidade de um método nulo

15

Para corrigir um erro em um aplicativo, modifiquei um método chamado postLoginadicionando uma chamada a um método existente chamado getShoppingCart.

Código

protected void postLogin() {
  getShoppingCart();
}

No entanto, não sei ao certo qual é a melhor maneira de escrever um teste de unidade postLogin.

Abordagem 1

Use o check do Mockito para simplesmente verificar se o método foi chamado.

verify(mock).getShoppingCart();

Abordagem 2

Teste o efeito colateral da chamada do método, buscando o valor do carrinho de compras do usuário.

AssertNotNull(user.getShoppingCart());

Uma abordagem é melhor que a outra?

A_B
fonte
1
o que facilitar a compreensão do teste e manter o código limpo. Se você não tiver certeza do design de teste, que poderia também ser um sinal de que o projeto do código está desligado. Verifique se você está fazendo as seguintes perguntas: " Por que a adição dessa chamada de método corrige o erro? Essa é a maneira CERTA de corrigir esse erro?"
Caleb #
8
A menos que seu getShoppingCart()método tenha efeitos colaterais, você não precisa testar como ele é chamado. Se tiver efeitos colaterais, você realmente deve mudar seu nome, porque os getXXX()métodos convencionalmente devem ser idempotentes.
Jules
@Jules getNextValue? Indiscutivelmente, alguém poderia dizer "Não chame isso de getter; mude o nome para nextValue", mas eu já vi getNextusado antes. Talvez um exemplo melhor seja um objeto representando um elétron; o que acontece quando ligo getPosition? Ou pior,getPosition(); getVelocity();
Aaron

Respostas:

18

Eu normalmente preferiria o método 2.

Por quê? Como você deseja postLoginalterar algum estado do seu sistema, mas como ele realiza isso (e quais métodos chama internamente para isso) é apenas um detalhe da implementação, nada sobre o qual o seu teste de unidade deve fazer suposições. Então é melhor fazer seu teste apenas verificando o estado final.

Doc Brown
fonte
4

Eu mudaria o getShoppingCart para algo como initializeShoppingCart, o objetivo do método deve ser claro para quem o lê, sem a necessidade de verificar o que o método faz e os efeitos colaterais como esse podem causar um comportamento surpreendente para os usuários do método.

Se getShoppingCart estiver em outra classe e já tiver sido testado em unidade, eu usaria a abordagem 1 - não há necessidade de testar novamente o que já foi testado. Nesse caso, temos certeza de que o getShoppingCart funciona corretamente e queremos apenas garantir que seja chamado a partir do postLogin. Se alguém no futuro remover essa chamada, o teste falhará.

Se getShoppingCart for um método privado que não possa ser testado por si só, eu usaria a abordagem 2, para garantir que, quando postLogin for chamado, a funcionalidade desejada de getShoppingCart seja executada conforme o esperado.

Nastya S
fonte
1

Ao testar uma chamada de função (nula ou não) com efeito colateral, é mais completo testar se o efeito colateral não ocorre apenas, mas verificar se o efeito colateral (saída do sistema ou alteração de estado) é o desejado.

hotpaw2
fonte
1
Embora isso seja verdade, também vale a pena considerar que os detalhes do efeito colateral que ocorre podem fazer parte do estado interno de algum outro módulo e, ao verificar esses detalhes, você acoplaria seu teste não apenas ao módulo que está testando, mas também esse outro módulo, que pode levar a testes frágeis se esses detalhes provavelmente mudarem. Zombar da interface entre os módulos ajuda a evitar esse problema.
Jules
0

Não discutirei seu design, mas, no seu caso, eu adotaria a primeira abordagem, porque o teste de unidade é para testar quais métodos fazem tecnicamente, independentemente do trabalho deles no domínio, ou seja, o que o seu método postLoginfaz? Tecnicamente, ele chama, getShoppingCardentão você precisa testar o que realmente está chamando getShoppingCard, eu também criaria outro teste para getShoppingCardtestar o que ele faz e, se tiver efeitos colaterais, eu o verificarei dentro desse novo teste.

La VloZ Merrill
fonte
0

Você tem um erro no postLogin. Portanto, a primeira coisa que você deve fazer é criar um teste de unidade que, ao chamar o postLogin sem o conjunto esperado de informações, "falhará".

A partir da idéia acima, outra alternativa das 2 propostas é injetar as informações sobre o carrinho de compras como parâmetro. Se você não tiver as informações corretas, lança uma exceção desmarcada. Isso deixará claro que, sem os detalhes corretos, seu método está condenado.

Isso exigirá uma pequena alteração, onde o cliente que está chamando o postLogin agora é necessário para também passar as informações do carrinho de compras. Para mim, isso ainda é coerente agora que você vê que eles estão acoplados. Esse acoplamento será realizado pelo chamador.

Então você nem precisaria testar o getShoppingCart dentro do postLogin porque o método real em teste é o postLogin. É aquele que possui o bug e o único que requer correção e validação adequadas. Com a dependência injetada, você poderá testá-lo facilmente sob diferentes condições e confirmar que nenhum erro foi gerado.

gumol
fonte