Test unitari: asserzioni differite con Linq


18

Va bene aggiungere affermazioni differite come questa

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

Perché? Quindi posso iterare solo una volta anche con le dichiarazioni che prevedono la raccolta materializzata, ad esempio:

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Inoltre, potrebbe non essere solo Seleziona, ma un metodo con iteratore definito e con molti controlli e logica (ad es. Conteggio e filtro).

Il seme del dubbio è la complessità della lettura e del debug di tale codice in caso di fallimento del test.


1
Non farei affidamento su questo per i test, ma a volte va bene farlo nel codice di produzione se non esiste una soluzione migliore. Puoi renderti una funzione di aiuto sequence.WithSideEffect(item => Assert.IsCute(item))per renderla più pulita.
usr

@usr Sembra che tu abbia colto il difetto chiave in questo modo - Effetto collaterale di un iteratore.
SerG

Non devi ancora ripetere due volte, una volta per generare l'elenco e di nuovo per confrontarlo expectedKittens? Hai appena nascosto le iterazioni dietro le chiamate di metodo.
IllusiveBrian,

@IllusiveBrian In questo senso, nell'esempio, sì. È ancora meno che con l'aggiunta .All().
SerG

Risposte:


37

Va bene aggiungere affermazioni differite come questa [..]

No , non lo è. Perché? Perché se per qualsiasi motivo rimuovete la seconda affermazione, il test diventerebbe ancora verde e pensereste che funzioni ancora ma non funziona poiché la raccolta non verrà enumerata. Se hai due o più affermazioni indipendenti, continueranno a fare il loro lavoro anche se ne disabiliti una.

Considera questa combinazione:

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Ora, anche se disabiliti o rimuovi uno degli asserzioni, l'altro farebbe comunque il suo lavoro. Inoltre, se ti dimentichi di materializzare la raccolta, potrebbe richiedere più tempo per l'esecuzione ma funzionerà comunque. I test indipendenti sono più robusti e affidabili.

C'è anche un secondo no . Non sono sicuro di come altri framework lo gestiscano, ma se si utilizza la piattaforma MS Test, non si saprebbe quale test non è riuscito. Se fai doppio clic sul test fallito ti mostrerà CollectionAssertcome fallito ma in realtà è stato il nidificato Assertche è andato storto e sarà estremamente difficile eseguire il debug. Ecco un esempio:

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

Ciò significa che il primo test è effettivamente inutile perché non aiuta a trovare un bug. Non sai se è fallito perché un numero non era valido o perché entrambe le raccolte erano diverse.


Perché? Quindi posso iterare solo una volta anche con dichiarazioni in attesa di una raccolta materializzata

Mi chiedo perché te ne importi? Questi sono test unitari. Non è necessario ottimizzarne ogni singolo bit e di solito i test non richiedono milioni di articoli, quindi le prestazioni non dovrebbero essere un problema.

Dovrai mantenere tali test, quindi perché dovresti renderli più complessi del necessario? Scrivi affermazioni semplici che funzionano.


Se per qualche motivo è necessario seppellire un'asserzione nel flusso di controllo, un modo per assicurarsi che sia stata eseguita consiste nel mantenere un contatore / flag che viene incrementato / impostato su vero prima dell'asserzione nidificata. Successivamente, possiamo affermare che il flusso di controllo previsto è stato preso controllando questo contatore. Non perfetto, ma si rivolge in gran parte alla tua prima critica.
amon,

1
Inoltre, tu o qualcun altro torneresti all'asserzione differita tra 6 mesi e dovresti perdere tempo a capirlo.
DavidTheWin,

C'è qualcosa di sbagliato nel tuo esempio. La chiamata ToListripeterà l'enumerabile, no?
RubberDuck,

1
@RubberDuck sì, lo farà e fallirà comunque non al Assert.Failma ma al CollectionAsserte non sarai in grado di dire quale affermazione in realtà è andata storta. Voglio dire che VS non si concentrerà Assert.Failma sull'altro ... ora puoi eseguire il debug.
t3chb0t,
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.