L'uso di una costante come parametro di un metodo di dipendenza da prova dell'unità testata è errato?

2

Abbiamo un caso di test unitario in cui vogliamo affermare che dopo un'operazione login , SUT è in grado di chiamare un metodo su una delle sue dipendenze. Questa dipendenza è una NavigationManager e l'aspettativa è che chiami NavigationManager.NavigateTo(string) .

Fino a questo punto, stiamo prendendo in giro il NavigationManager per isolare SUT . Questo è il nostro metodo di prova:

var calledNavigatedToMethod = false;
nmMock.Setup(nm => nm.NavigateTo(NavigableScreens.MyNextScreen)).Callback(() => calledNavigatedToMethod = true);

SUT.Login();

Assert.IsTrue(calledNavigatedToMethod);

Come puoi vedere, NavigableScreens.MyNextScreen è una costante, che ci fa pensare che questa non sia una dipendenza , quindi non dovrebbe essere iniettata / derisa. Stiamo semplicemente testando che quando viene chiamato SUT.Login () , la sua dipendenza chiama un metodo con detta costante.

La nostra confusione è che, nel momento in cui stavamo scrivendo il test unitario, NavigableScreens.MyNextScreen non era ancora definito, il che ha reso il test affidabile sulla sua esistenza, e ci ha fatto pensare che per questo motivo dovrebbe essere iniettato / deriso .

Un argomento proposto è che poiché è una dipendenza del SUT , DEVE esistere , il che significa che l'utilizzo di questa costante nel Test Case è perfettamente soddisfacente, poiché è esattamente la stessa cosa che chiama NavigationManager.NavigateToMyNextScreen() nel modo in cui se il metodo non esiste al momento della scrittura del test, avremmo lo stesso problema, quindi DEVE esistere.

La domanda sarebbe: l'uso di questa costante nel test case è sbagliato, rendendolo un test non unitario?

    
posta Christopher Francisco 12.07.2015 - 01:02
fonte

2 risposte

3

Se i requisiti attuali sono quelli dopo il login, devi sempre navigare verso la schermata indicata dalla costante NavigableScreens.MyNextScreen , quindi molto probabilmente non è una dipendenza che dovrebbe essere iniettata. È solo un valore che passi comunque ad un'altra funzione.

Tuttavia, NavigationManager sembra essere una classe con un bel po 'di funzionalità al suo interno. Quel è qualcosa che dovrebbe essere iniettato come dipendenza nel SUT (a meno che il tuo SUT non sia NavigationManager stesso).
Detto questo, il tuo test unitario va bene.

Quando si guarda a dove usare finte / matrici / falsi nei test di unità, ci sono alcune considerazioni da tenere a mente (oltre a richiedere DI per scopi diversi dalla testabilità):

  1. Il codice che non fa parte rigorosamente del SUT è stabile e ben collaudato abbastanza da non essere in grado di scoprire i problemi con esso? In caso contrario, dovrebbe essere deriso.

  2. Le operazioni eseguite dal codice aggiuntivo sono complesse o richiedono molto tempo da poter influire sulla velocità di esecuzione dei miei test unitari? Se lo sono, dovresti prendere in giro queste operazioni.

  3. L'operazione è eseguita dal codice extra relativo alla persistenza? Se è così, dovrebbero davvero essere derisi. Quando i database o altri meccanismi di persistenza entrano in scena, diventa davvero difficile mantenere i test indipendenti l'uno dall'altro. Vuoi davvero quella complessità solo quando stai testando tali meccanismi.

risposta data 12.07.2015 - 12:14
fonte
2

Una prospettiva è che hai sempre bisogno di una giustificazione per deridere, piuttosto che una giustificazione per usare la vera dipendenza.

I test derubati sono, in poche parole, peggio dei test reali;

  • testano meno
  • richiede più manutenzione
  • è più difficile da scrivere
  • produce sia falsi positivi che falsi negativi
  • hanno risultati che sono più difficili da interpretare
  • funziona più lentamente (può variare a seconda dell'ambiente, ma generalmente fa tutto in un modo altamente dinamico che batte la maggior parte degli ottimizzatori)

A volte questi trade-off valgono la pena; le alternative sono più lente, meno affidabili o pianamente impossibili. Ma, chiaramente, nessuno di questi si applica nel caso di una costante di stringa semplice. Quindi qui puoi tranquillamente dire che non c'è giustificazione per deridere quella dipendenza piuttosto che usare la cosa reale.

Il corollario è il fatto che anche tu stia considerando che, come opzione in quel caso scontato, rivela che probabilmente stai sfruttando eccessivamente i mock. Prova a esaminare la tua suite di test e pensa

What would happen if I replaced this usage of a mock with the real thing?

Would it perhaps run faster, detect more issues, give a better description of failures?

Would it be more refactorable, shorter, more reliable, provide better design guidance?

Se trovi molti casi in cui l'altro modo di scrivere il test è migliore, nel senso di cui sopra, allora è un argomento strong che dovrebbero essere scritti in questo modo.

    
risposta data 12.07.2015 - 23:54
fonte

Leggi altre domande sui tag