Existe algum valor em escrever um teste de unidade que seja um subconjunto de outro teste?

15

Para dar um exemplo um pouco artificial, digamos que eu queira testar se uma função retorna dois números e que o primeiro é menor que o segundo:

def test_length():
    result = my_function()
    assert len(result) == 2

def test_order()
    a, b = my_function()
    assert a < b

Aqui, se test_lengthfalhar, test_ordertambém falhará. É uma prática recomendada escrever test_lengthou pular?

EDIT: observe que, nessa situação, os dois testes são independentes em sua maioria, cada um pode ser executado isoladamente ou em ordem inversa, isso não importa. Portanto, nenhuma dessas perguntas anteriores

é uma duplicata da acima.

Mihai
fonte
2
possível duplicata do teste
2
@ GlenH7 - esta parece ser uma pergunta diferente. O outro é "se você tem funções em que Achama Be retorna o mesmo resultado, deve testar ambos Ae B". Isso se refere mais à sobreposição dos testes, e não às funções sob teste. (Embora seja confuso como eles são nomeados atualmente).
Telastyn
1
Estritamente falando, esses testes não são realmente sobrepostos (eles não têm dependência de sucesso). Uma função lambda: type('', (), {'__len__': lambda self: 2})()passará a primeira, mas não a segunda.
liori 12/01/2015
1
@ GlenH7: FWIW, eu realmente não mudar a pergunta, apenas tentei fazer isso mosquito-safe ;-): (@gnat sem ofensa, apenas brincando!)
Doc Brown

Respostas:

28

Pode haver valor, mas isso é um pouco de cheiro. Seus testes não são bem isolados (já que test_orderrealmente testam duas coisas) ou você está sendo dogmático demais (fazendo dois testes testando a mesma coisa lógica).

No exemplo, eu mesclaria os dois testes. Sim, significa que você tem várias declarações. Que pena. Você ainda está testando uma única coisa - o resultado da função. Às vezes, no mundo real, isso significa fazer duas verificações.

Telastyn
fonte
Votei na sua resposta, embora ela perca um ponto menor. No Python, o segundo teste também falhará quando my_functionnão retornar exatamente dois valores, sem nenhuma afirmação - porque a atribuição resultará em uma exceção. Portanto, não há realmente a necessidade de usar várias declarações e duas verificações para testar a mesma coisa.
Doc Brown
@DocBrown - Eu assumi isso, mas não estou familiarizado com as mensagens de erro do Python para saber se pode haver valor em ter uma falha de afirmação em vez de exceção / erro aleatório por motivos informativos.
Telastyn
Acho que na situação atual a mensagem de erro provavelmente seria informativa o suficiente. Mas, em geral, esse pode não ser o caso. É por isso que concordo que a abordagem geral para um caso como esse deve ser pensar em uma "mesclagem", usando duas afirmações. Se o teste puder ser mais simplificado, deixando de fora uma das afirmações, tudo bem.
Doc Brown
5
@DocBrown O outro valor na verificação explícita com uma afirmação é que fica claro para qualquer pessoa que examina o teste que esta é uma falha do código em teste, e não o teste em si. Quando meus testes encontram exceções inesperadas, sempre preciso dedicar algum tempo para descobrir qual deles está realmente errado.
Chris Hayes
@ ChrisHayes: eu escrevi "não há necessidade", não "não há valor" nele.
Doc Brown
5

Seus testes devem ser explícitos. Não é completamente inferido que, se text_length falhar, test_order falhará.

Não tenho certeza de como foi publicado em Python, mas se len(result)for 3, o primeiro falhará, mas o segundo poderá passar (e, se não for em Python, em idiomas como JavaScript, com certeza).

Como você disse, você deseja testar se a função retorna dois números e se eles estão em ordem. São dois testes.

Fantasma de Madara
fonte
1
It's not completely inferred that if text_length fails test_order fails- no Python, isso dará uma exceção.
Doc Brown
Eu acho que a pergunta é sobre o caso em que falha test_lengthimplica falha de test_order. O fato de um par semelhante de testes escritos em Javascript não se comportar da mesma forma que esses dois testes python é irrelevante.
Dawood diz que restabelece Monica
2
@ DavidWallace: lembre-se, a pergunta era "É uma prática recomendada escrever test_length ou ignorá-la"? Em Javascript, você precisa dos dois testes para garantir que não perdeu um problema (quando não mescla os dois testes em um). No Python, você pode omitir com segurança o primeiro (que é negado na primeira frase desta resposta e declarado como "Não tenho certeza" na segunda). Honestamente, uma boa resposta parece diferente. No entanto, não neguei essa resposta, pois a parte boa é na verdade a menção do JavaScript.
Doc Brown
4
@ DavidWallace: como estamos aqui no programmers.com, não no stackoverflow.com, o IMHO fornece uma resposta que pode ser aplicada a mais de um idioma e melhor do que uma resposta apenas para um idioma específico. Porém, ao se referir a um idioma específico, a resposta deve estar correta sobre o idioma e não misturar algumas propriedades.
Doc Brown
1
A questão é: "vale a pena escrever um teste que seja um subconjunto de outro teste", e esta resposta diz: "em alguns idiomas, nenhum dos seus testes é um subconjunto do outro" e chega à conclusão de que ambos os testes são portanto, necessário. Ele lê para mim como se alguém dissesse: "seu código não é compilado em C ++ e, além disso, em C ++, uma função pode retornar apenas um valor, assim você não precisa testá-lo, retorna dois. Somente escreva um teste". ;-)
Steve Jessop
2

O único valor test_lengthaqui é que, se tudo passar, sua presença indica que o "comprimento" foi testado.

Portanto, é realmente desnecessário ter esses dois testes. Mantenha apenas, test_ordermas considere renomeá-lo test_length_and_order.

Aliás, acho o uso de nomes que começam com testum pouco desajeitado. Sou um forte defensor dos nomes dos testes que descrevem a condição que você está afirmando.

Dawood diz restabelecer Monica
fonte
1
A testverruga é significativa para a estrutura de teste do Python. Qual dos necessidade claro que não mudar se você é um fã dele, mas não altera o peso do argumento necessário para impedir que alguém a usá-lo ;-)
Steve Jessop
@SteveJessop Sim, continuo esquecendo que é necessário. Quando eu estava escrevendo testes em Python há um tempo atrás, adquiri o hábito de começar todos com test_that_, como test_that_return_values_are_in_ordere assim por diante. Talvez uma versão futura da estrutura de teste resolva esse requisito de alguma forma.
Dawood diz que restabelece Monica
@ DavidWallace: você pode alterar o prefixo, se quiser.
Lie Ryan
1

Eu deixaria esses testes separados se é assim que eles evoluíram. Sim, test_orderé provável que falhe sempre test_lengthque ocorrer , mas você definitivamente sabe o porquê.

Concordo também que, se o test_orderprimeiro apareceu e você encontrou uma falha testável, o resultado possivelmente não foi de dois valores, adicionando essa verificação como asserte renomeando o teste para test_length_and_orderfazer sentido.

Se você também tivesse que verificar se os tipos de valores retornados eram números inteiros, incluiria isso neste teste de resultados "abrangente".

Mas observe que agora você tem uma bateria de testes para obter o resultado de my_function(). Se houver vários contextos (ou, mais provavelmente, vários parâmetros) para testar isso agora poderá ser uma sub-rotina para testar todos os resultados my_function().

No entanto, quando escrevo testes de unidade, normalmente testo os casos extremos e ruins separadamente das boas entradas e saídas normais (em parte porque a maioria dos meus testes de "unidade" são geralmente mini testes de integração) e geralmente com várias afirmações, que são quebradas apenas em testes separados, se falharem nas maneiras em que acho que quero mais informações sem depuração.

Então eu provavelmente começaria com seus testes separados e expandiria test_lengthpara test_length_and_typese deixaria test_orderseparados, supondo que o último seja visto como "processamento normal".

Mark Hurd
fonte