Todo método deve retornar um valor para o Teste de Unidade?

12

Estou aprendendo a criar testes de unidade simples para eventualmente (e espero) começar a fazer apenas TDD; por enquanto estou tentando escrever testes para códigos já escritos para ver o que pode causar problemas. Este é um deles.

Digamos que eu tenho essa classe simples (com TypeScript-> Javascript):

class PrivateStuff {
    greeting: string;
    private _thisIsPrivate;

    constructor(isPrivate: boolean) {
        this._thisIsPrivate = isPrivate;
    }

    setPrivate(option) {
        this._thisIsPrivate = option;
        console.log("_thisIsPrivate changed to : " + option);
    }

    getPrivate() {
        console.log("_thisIsPrivate is : " + this._thisIsPrivate);
        return this._thisIsPrivate;        
    }
}

E eu uso desta maneira:

let privateStuff = new PrivateStuff(false);

let buttonSet = document.createElement('button');
buttonSet.textContent = "Set True";
buttonSet.onclick = function () {
    privateStuff.setPrivate(true);
}

let buttonGet = document.createElement('button');
buttonGet.textContent = "Get";
buttonGet.onclick = function() {
    console.log(privateStuff.getPrivate());
}
document.body.appendChild(buttonSet);
document.body.appendChild(buttonGet);

setPrivate()não precisa retornar nada, mas por isso não posso testá-lo. Ao criar um teste de unidade, devo refatorar o código?

Se eu estivesse usando TDD, sempre deveria criar métodos que retornam algo apenas para poder testá-lo? Ou estou faltando alguma coisa?

PS Você pode ver e executar o código aqui

distante
fonte
4
Se você setPrivate, o valor de getPrivate não informa se funcionou?
22417 JeffOf
@ JeffO Sim, agora vejo que não preciso apenas usar o retorno da função para verificar se funcionou.
distante
"setPrivate () não precisa retornar nada, mas por isso não posso testá-lo." Induz algum efeito observável? Nesse caso, você pode testá-lo. Caso contrário, não há interesse em testá-lo (e não há interesse em implementá-lo).
precisa saber é o seguinte
@mgoeminne E se o método for nulo e gravar no banco de dados / log ou enviar uma mensagem para outro objeto como seu único efeito?
Andres F.
@AndresF. Você pode ler do banco de dados / log ou zombar do outro objeto para confirmar que os dados foram enviados. Pode não ser um teste de "unidade", mas não é isso que realmente importa.
Jacob Raihle 21/03

Respostas:

21

Acho que seu equívoco aqui é que um "sujeito em teste" deve ser sempre um método por si só. Mas isso não é verdade, embora alguns métodos possam ser testados sem o uso de outros métodos, o tamanho típico de um SUT é uma classe ou alguns métodos e funções de interação de uma classe. Portanto, se você possui um método que altera o estado interno de um objeto, sempre deve haver alguma alteração visível externamente no comportamento desse objeto (caso contrário, não faria sentido ter o método em primeiro lugar). E em um teste de unidade, você pode validar exatamente esse comportamento.

Por exemplo, digamos que você tenha uma classe NumberFormattercom a responsabilidade de formatar números de ponto flutuante de uma maneira predefinida. Vamos supor que ele contenha um método FormatToString(double d). Vamos assumir ainda que ele tem um método setDecimalSeparator, mas não getDecimalSeparator. No entanto, você pode facilmente escrever um teste se após uma chamada para setDecimalSeparatoro método FormatToStringse comportar da maneira desejada. Esse teste pode ser assim

  var nf = new NumberFormatter();
  nf.setDecimalSeparator(".");
  AssertEqual("12.34",nf.FormatToString(12.34))
  nf.setDecimalSeparator(",");
  AssertEqual("12,34",nf.FormatToString(12.34))

Portanto, este é um teste significativo de setDecimalSeparator, um método sem um valor de retorno.

Doc Brown
fonte
Entendo, portanto, no meu exemplo irrealista, eu poderia usar a função ´getPrivate () ´ para ver se ´_isIsPrivate´ teve alterações e desconfiança de que ´getPrivate () 'funciona, mas em um cenário mais real, devo testar o objeto que está sendo alterado . Obrigado por sua explicação clara!
distante 15/02