C'è qualche valore nella scrittura di un unit test che è un sottoinsieme di un altro test?


15

Per fare un esempio leggermente inventato, diciamo che voglio provare che una funzione restituisce due numeri e che il primo è più piccolo del secondo:

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

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

Qui, se test_lengthfallisce, allora test_orderfallirà anche. È una buona pratica scrivere test_lengtho saltare?

EDIT: nota che in questa situazione, entrambi i test sono per lo più indipendenti l'uno dall'altro, ognuno può essere eseguito in modo isolato o potrebbe essere eseguito in ordine inverso, questo non ha importanza. Quindi nessuna di queste precedenti domande

è un duplicato di quello sopra.



2
@ GlenH7 - questa sembra una domanda diversa. L'altro è "se hai funzioni in cui Achiama Be restituisce lo stesso risultato, dovresti testare entrambi Ae B". Si tratta più delle sovrapposizioni dei test piuttosto che delle funzioni sotto test. (Anche se è confuso come sono attualmente chiamati).
Telastyn,


1
A rigor di termini, questi test non sono realmente sovrapposti (non hanno dipendenza dal successo). Una funzione lambda: type('', (), {'__len__': lambda self: 2})()passerà la prima, ma non la seconda.
liori,

1
@ GlenH7: FWIW, non ho davvero cambiato la domanda, ho solo cercato di renderlo sicuro per i moscerini ;-) (@gnat: senza offesa, sto solo scherzando!)
Doc Brown,

Risposte:


28

Può esserci valore, ma questo è un po 'di odore. O i tuoi test non sono ben isolati (dal momento test_orderche testano due cose) o sei troppo dogmatico nei tuoi test (facendo due test testare la stessa cosa logica).

Nell'esempio, unirei i due test insieme. Sì, significa che hai più asserzioni. Peccato. Stai ancora testando una sola cosa: il risultato della funzione. A volte nel mondo reale ciò significa fare due controlli.


Ho votato a fondo la tua risposta anche se manca un punto minore. In Python, anche il secondo test fallirà quando my_functionnon restituirà esattamente due valori, senza alcuna asserzione, poiché l'assegnazione comporterà un'eccezione. Quindi in realtà non è necessario utilizzare più assert e due controlli per testare la stessa cosa.
Doc Brown,

@DocBrown - Ho assunto lo stesso, ma non ho familiarità con i messaggi di errore di Python per sapere se può esserci valore nell'avere un fallimento dell'asserzione invece dell'eccezione / errore casuale per motivi informativi.
Telastyn,

Penso che nella situazione attuale il messaggio di errore sia probabilmente abbastanza informativo. Ma in generale, potrebbe non essere così. Ecco perché sono d'accordo con te sul fatto che l'approccio generale per un caso come questo dovrebbe essere quello di pensare a una "fusione", usando due asserzioni. Se si scopre che il test può essere ulteriormente semplificato tralasciando una delle affermazioni, va bene.
Doc Brown,

5
@DocBrown L'altro valore nel controllo esplicito con un'asserzione è che diventa chiaro a chiunque stia esaminando il test che si tratta di un errore del codice testato e non del test stesso. Quando i miei test incontrano eccezioni inaspettate, devo sempre dedicare un po 'di tempo a capire quale sia effettivamente sbagliato.
Chris Hayes,

@ChrisHayes: ho scritto "non c'è bisogno", non "non c'è valore" in esso.
Doc Brown,

5

I tuoi test dovrebbero essere espliciti. Non si deduce del tutto che se text_length fallisce test_order fallisce.

Non sono sicuro di come vada in Python che hai pubblicato, ma se len(result)è 3 allora il primo fallirà ma il secondo potrebbe passare (e se non in Python, allora in lingue come JavaScript sicuramente).

Come hai detto, vuoi verificare che la funzione restituisca due numeri e che siano in ordine. Due prove lo sono.


1
It's not completely inferred that if text_length fails test_order fails- in Python, lo è, ti darà un'eccezione.
Doc Brown,

Penso che la domanda riguardi il caso in cui il fallimento di test_lengthimplica il fallimento di test_order. Il fatto che una coppia simile di test scritti in Javascript non si comporterebbe allo stesso modo di questi due test di Python è in qualche modo irrilevante.
Dawood dice di ripristinare Monica il

2
@DavidWallace: ricorda, la domanda era "È una buona pratica scrivere test_length o saltarlo"? In Javascript, hai bisogno di entrambi i test per assicurarti di non aver perso un problema (quando non unisci i due test in uno). In Python, puoi tranquillamente omettere il primo (che è negato nella prima frase di questa risposta e dichiarato come "Non sono sicuro" nella seconda). Onestamente, una buona risposta sembra diversa. Tuttavia, non ho sottovalutato questa risposta poiché la parte buona è in realtà la menzione di JavaScript.
Doc Brown,

4
@DavidWallace: dal momento che siamo qui programmers.com, non su stackoverflow.com, IMHO che fornisce una risposta che potrebbe essere applicata a più di una lingua è meglio di una risposta solo per una determinata lingua. Ma quando ci si riferisce a una lingua specifica, la risposta dovrebbe essere corretta sulla lingua e non confondere alcune proprietà.
Doc Brown,

1
Il fatto è che la domanda è "vale la pena scrivere un test che è un sottoinsieme di un altro test", e questa risposta dice: "in alcune lingue, nessuno dei tuoi test è un sottoinsieme dell'altro" e quindi arriva alla conclusione che entrambi i test sono quindi necessario. Mi sembra che qualcuno abbia detto: "il tuo codice non si compila affatto in C ++ e inoltre, in C ++ una funzione può restituire solo un valore, quindi non è necessario testarlo restituisce due. Scrivere solo un test" ;-)
Steve Jessop,

2

L'unico valore di test_lengthquesto è che, se tutto passa, la sua stessa presenza indica che la "lunghezza" è stata testata.

Quindi non è davvero necessario avere entrambi questi test. Conserva solo test_orderma considera di rinominarlo test_length_and_order.

Per inciso, trovo l'uso di nomi che iniziano con testun po 'goffo. Sono un forte sostenitore dei nomi dei test che descrivono effettivamente la condizione che stai affermando.


1
La testverruca è significativa per il framework di test di Python. Il che ovviamente non deve cambiare se sei un fan, ma cambia il peso dell'argomento necessario per impedire a qualcuno di usarlo ;-)
Steve Jessop,

@SteveJessop Sì, continuo a dimenticare che è necessario. Quando stavo scrivendo test Python qualche tempo fa, ho preso l'abitudine di iniziarli tutti con test_that_, simili test_that_return_values_are_in_ordere così via. Forse una versione futura del framework di test funzionerà in qualche modo con questo requisito.
Dawood dice di reintegrare Monica il

@DavidWallace: è possibile modificare il prefisso se lo si desidera.
Sdraiati Ryan il

1

Lascerei separati questi test se è così che si sono evoluti. Sì, test_orderè probabile che fallisca ogni volta test_length, ma sicuramente sai perché.

Concordo anche sul fatto che se l' test_orderapparisse prima e tu avessi trovato un errore verificabile fosse che il risultato probabilmente non era due valori, aggiungere quel controllo come un asserte rinominare il test per avere test_length_and_orderun senso.

Se dovessi anche verificare che i tipi di valori restituiti fossero numeri interi, lo includerei in questo test dei risultati "omnibus".

Ma nota ora che hai una batteria di test per il risultato di my_function(). Se ci sono più contesti (o, più probabilmente, più parametri) per testare questo ora può essere una subroutine da cui testare tutti i risultati my_function().

Tuttavia, quando scrivo unit test, di solito collaudo il fronte e i casi negativi separatamente da input e output normali (in parte perché la maggior parte dei miei test "unit" sono spesso mini test di integrazione), e spesso con affermazioni multiple, che sono solo interrotte in test separati se falliscono nei modi in cui trovo che voglio ulteriori informazioni senza debug.

Così Io probabilmente iniziare con i test separati e ampliare test_lengthper test_length_and_typese lasciare test_orderseparati, assumendo quest'ultimo è visto come "l'elaborazione normale".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.