Sabemos que escrever testes JUnit demonstra um caminho específico através do seu código.
Um dos meus associados comentou:
A gravação manual de testes de unidade é a Prova por exemplo .
Ele vinha do fundo de Haskell, que possui ferramentas como o Quickcheck e a capacidade de raciocinar sobre o comportamento do programa com tipos .
Sua implicação era que existem muitas outras combinações de entradas que não são experimentadas por esse método para as quais seu código não foi testado.
Minha pergunta é: Os testes de unidade de gravação manual são prova por exemplo?
unit-testing
junit
Hawkeye
fonte
fonte
Respostas:
Se você escolher aleatoriamente entradas para teste, suponho que seja possível que você esteja exercendo uma falácia lógica de Prova por Exemplo.
Mas bons testes de unidade nunca fazem isso. Em vez disso, eles lidam com intervalos e casos extremos.
Por exemplo, se você escrevesse testes de unidade para uma função de valor absoluto que aceita um número inteiro como entrada, não seria necessário testar todos os valores possíveis de entrada para provar que o código funciona. Para obter um teste abrangente, você precisaria apenas de cinco valores: -1, 0, 1 e os valores máximo e mínimo para o número inteiro de entrada.
Esses cinco valores testam todos os intervalos e bordas possíveis da função. Você não precisa testar todos os outros valores de entrada possíveis (ou seja, todos os números que o tipo inteiro possa representar) para obter um alto nível de confiança de que a função funciona para todos os valores de entrada.
fonte
int foo(int x) { return 1234/(x - 100); }
. Observe também que (dependendo do que você está testando), pode ser necessário garantir que a entrada inválida ("fora do intervalo") retorne resultados corretos (por exemplo, que `` find_thing (thing) `retorne corretamente algum tipo de status" não encontrado " se a coisa não foi encontrada).-Inf
,Inf
,NaN
,1e-100
,-1e-100
,-0
,2e200
... Eu prefiro não tem que fazer todos aqueles manualmente.Qualquer teste de software é como "Prova por exemplo", não apenas testes de unidade usando uma ferramenta como JUnit. E isso não é nova sabedoria, há uma citação de Dijkstra de 1960, que diz essencialmente o mesmo:
(basta substituir as palavras "shows" por "provas"). No entanto, isso também é verdade para ferramentas que geram dados de teste aleatórios. O número de entradas possíveis para uma função do mundo real é geralmente maior em ordens de magnitudes do que o número de casos de teste que se pode produzir e verificar em relação a um resultado esperado dentro da idade do universo, independentemente do método de geração desses casos. mesmo se alguém usar uma ferramenta geradora para produzir muitos dados de teste, não há garantia de não perder o caso de teste que poderia ter detectado um determinado bug.
Às vezes, testes aleatórios podem revelar um bug que foi ignorado pelos casos de teste criados manualmente. Mas, em geral, é mais eficiente criar testes cuidadosamente para a função a ser testada e garantir que um usuário obtenha uma cobertura completa de código e ramificação com o menor número possível de casos de teste. Às vezes, é uma estratégia viável combinar testes gerados manualmente e aleatoriamente. Além disso, ao usar testes aleatórios, é preciso ter o cuidado de obter os resultados de maneira reproduzível.
Portanto, os testes criados manualmente não são de forma alguma pior que os testes gerados aleatoriamente, geralmente o contrário.
fonte
Escrever testes manualmente é "prova por exemplo". Mas o QuickCheck também é assim e, em certa medida, os sistemas de tipos. Qualquer coisa que não seja uma verificação formal direta será limitada no que diz sobre seu código. Em vez disso, você deve pensar em termos do mérito relativo das abordagens.
Testes generativos, como o QuickCheck, são realmente bons para varrer um amplo espaço de entradas. Também é muito melhor para lidar com casos extremos do que com testes manuais: as bibliotecas de testes generativas terão mais experiência com isso do que você. Por outro lado, eles apenas falam sobre invariantes, não sobre resultados específicos. Portanto, para validar que seu programa está obtendo os resultados corretos, você ainda precisa de alguns testes manuais para verificar isso
foo(bar) = baz
.fonte