Existe a necessidade de manter testes para funções simples (autocontidas)?

36

Considere isso:

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

Suponha que você escreva vários testes para a função acima e prove para si mesmo e para os outros que "funciona".

Por que não remover esses testes e viver felizes para sempre? Meus pontos são que algumas funções não precisam ser testadas continuamente após terem sido provadas que funcionam. Eu estou procurando por contra-pontos que afirmam, sim essas funções ainda precisam ser testadas, porque: ... Ou que sim, estas não precisam ser testadas ...

    
por Dennis 18.08.2015 / 00:04
fonte

7 respostas

78

Teste de regressão

É tudo sobre testes de regressão .

Imagine o próximo desenvolvedor analisando seu método e percebendo que você está usando números mágicos. Foi-lhe dito que os números mágicos são maus, então ele cria duas constantes, uma para o número dois e outra para o número três - não há nada errado em fazer essa mudança; não é como se ele estivesse modificando sua implementação já correta.

Sendo distraído, ele inverte duas constantes.

Ele confirma o código e tudo parece funcionar bem, porque não há testes de regressão em execução após cada confirmação.

Um dia (pode ser semanas depois), algo quebra em outro lugar. E por outro lado, quero dizer na localização completamente oposta da base de código, que parece não ter nada a ver com a função polynominal . Horas de depuração dolorosa levam ao culpado. Durante esse tempo, o aplicativo continua a falhar na produção, causando muitos problemas aos seus clientes.

Manter os testes originais que você escreveu pode evitar essa dor. O desenvolvedor distraído iria cometer o código, e quase imediatamente ver que ele quebrou alguma coisa; esse código nem chega à produção. Os testes unitários serão adicionalmente muito precisos sobre a localização do erro . Resolver isso não seria difícil.

Um efeito colateral ...

Na verdade, a maioria das refatorações é strongmente baseada em testes de regressão. Faça uma pequena mudança. Teste. Se passar, tudo está bem.

O efeito colateral é que, se você não tem testes, praticamente qualquer refatoração se torna um grande risco de quebrar o código. Dado que são muitos casos, já é difícil explicar ao gerenciamento que a refatoração deve ser feita, seria ainda mais difícil fazer isso depois que suas tentativas anteriores de refatoração introduzirem vários bugs.

Por ter um conjunto completo de testes, você está encorajando a refatoração e, portanto, um código mais limpo. Sem riscos, torna-se muito tentador refatorar mais, regularmente.

Alterações nos requisitos

Outro aspecto essencial é que os requisitos mudam. Você pode ser solicitado a para lidar com números complexos e, de repente, você precisa pesquisar o log de controle de versão para encontrar os testes anteriores, restaurá-los e começar a adicionar novos testes.

Por que todo esse incômodo? Por que remover testes para adicioná-los depois? Você poderia tê-los mantido em primeiro lugar.

    
por 18.08.2015 / 00:31
fonte
45

Porque nada é tão simples que não possa haver bugs.

Seu código, embora pareça sem erros. Na verdade, é uma representação programática simples de uma função polinomial.

Exceto que tem um bug ...

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

$x não está definido como uma entrada para seu código e, dependendo do idioma ou do tempo de execução, ou do escopo, sua função pode não funcionar, pode causar resultados inválidos ou pode bater em uma nave espacial .

Adendo:

Embora você possa considerar que o seu código está livre de erros por enquanto, quanto tempo isso permanece, é difícil dizer. Embora possa ser argumentado que não vale a pena escrever um teste para um trecho de código tão trivial, tendo já escrito o teste, o trabalho é feito e excluí-lo é excluir uma proteção segura tangível.

De nota adicional são serviços de cobertura de código (como coveralls.io) que dão uma boa indicação da cobertura que uma suíte de testes oferece. Cobrindo cada linha de código, você dá uma métrica decente da quantidade (se não a qualidade) do teste que você executa. Em combinação com muitos pequenos testes, estes serviços, pelo menos, dizem onde não procurar um bug quando isso acontece.

Por fim, se você já tiver um teste escrito, mantenha-o . Porque o espaço ou a economia de tempo da exclusão provavelmente será muito menor do que a dívida técnica mais tarde, se ocorrer um erro.

    
por 18.08.2015 / 07:41
fonte
21

Sim. Se pudéssemos dizer com 100% de confiança, com certeza: essa função nunca será editada e nunca será executada em um contexto que poderia causar uma falha - se pudéssemos dizer isso, poderíamos abandonar os testes e economizar alguns milissegundos em cada Construção de IC.

Mas não podemos. Ou não podemos com muitas funções. E é mais simples ter uma regra de executar todos os testes o tempo todo do que se esforçar em determinar com exatidão com que limite de confiança estamos satisfeitos e exatamente quanta confiança temos na imutabilidade e infalibilidade de qualquer função.

E o tempo de processamento é barato. Esses milésimos de segundo salvos, até mesmo multiplicados muitas vezes, não chegam perto o suficiente para justificar o tempo gasto em todas as funções: temos confiança suficiente de que nunca mais precisamos testá-lo novamente?

    
por 18.08.2015 / 00:29
fonte
12

Tudo dito nas outras respostas está correto, mas adicionarei mais uma.

Documentação

Testes de unidade, se bem escritos, podem explicar a um desenvolvedor exatamente o que uma função faz, quais são suas expectativas de entrada / saída e, mais importante, qual comportamento pode ser esperado dela.

Pode tornar mais fácil detectar um erro e diminuir a confusão.

Nem todo mundo se lembra de polinômios, geometria, ou mesmo álgebra :) Mas um bom teste de unidade foi registrado para que o controle de versão se lembrasse de mim.

Para um exemplo de como pode ser útil como documentação, veja a introdução de Jasmine: link alguns segundos para carregar e, em seguida, role até a parte inferior. Você verá toda a API do Jasmine documentada como saída de teste de unidade.

[Atualização com base no feedback do @Warbo] Os testes também têm a garantia de estarem atualizados, já que, se não estiverem, eles falharão, o que geralmente causará uma falha de compilação se o IC for usado. A documentação externa muda independentemente do código e, portanto, não está necessariamente atualizada.

    
por 18.08.2015 / 04:04
fonte
2

Verificação da realidade

Eu tenho estado em ambientes desafiadores onde o teste é "perda de tempo" durante o orçamento e cronograma, e depois "uma parte fundamental da garantia de qualidade" quando o cliente está lidando com bugs, então minha opinião é mais fluida do que outras ser.

Você tem um orçamento. Seu trabalho é obter o melhor produto possível com esse orçamento, para qualquer definição de "melhor" que você possa juntar (não é uma palavra fácil de definir). Fim da história.

O teste é uma ferramenta no seu inventário. Você deve usá-lo, porque é uma boa ferramenta , com uma longa história de salvar milhões, ou talvez até bilhões de dólares. Se tiver uma chance, você deve adicionar testes a essas funções simples. Pode salvar sua pele algum dia.

Mas no mundo real, com restrições de orçamento e cronograma, isso pode não acontecer. Não se faça escravo do procedimento. As funções de teste são boas, mas em algum momento, suas horas-homem podem ser melhor gastas escrevendo a documentação do desenvolvedor em palavras, em vez de codificar, para que o próximo desenvolvedor não precise de testes. Ou pode ser melhor gasto refatorando a base de código para que você não precise manter a mesma dificuldade de uma fera. Ou talvez esse tempo seja mais bem gasto conversando com seu chefe sobre o orçamento e o cronograma, para que ele compreenda melhor para o que está procurando quando a próxima rodada de financiamento chegar ao fim.

O desenvolvimento de software é um equilíbrio. Sempre conte o custo de oportunidade de qualquer coisa que você esteja fazendo para garantir que não haja uma maneira melhor de gastar seu tempo.

    
por 18.08.2015 / 17:50
fonte
0

Sim, mantenha os testes, mantenha-os em execução e mantenha-os em trânsito.

Testes de unidade estão lá para proteger você (e outros) de si mesmo (e de si mesmos).

Por que manter os testes é uma boa ideia?

  • Validar a funcionalidade dos requisitos anteriores em face de novos requisitos e funcionalidades adicionais
  • Verifique se os exercícios de refatoração estão corretos
  • Documentação interna - é assim que se espera que o código seja usado
  • Teste de regressão, as coisas mudam
    • As alterações quebram o código antigo?
    • As alterações exigem mais solicitações de alteração ou atualizações para as funções ou códigos atuais?
  • Dado que os testes já estão escritos, mantenha-os; é tempo e dinheiro já gastos que reduzirão os custos de manutenção mais abaixo na linha
por 18.08.2015 / 11:19
fonte
-1

Documentação do desenvolvedor

  • Como eu (como outro desenvolvedor) sei que isso foi testado?
  • Se eu quiser corrigir um bug na função self contained , como sei que não estou apresentando um bug que você já havia considerado?
  • Indicador de complexidade: o número de testes pode ser uma boa medida de quão complexo é algo. Isso pode indicar que você não deve tocá-lo porque é maduro e estável ou que está inchado e acoplado.

Documentação do usuário

  • Documento pendente, posso ver se {zero, valores negativos, conjuntos vazios, etc} são aceitos e qual é o valor de retorno esperado.
  • Também dá um bom exemplo de como eu deveria usar o objeto / função
por 18.08.2015 / 23:17
fonte