Devo testare un metodo che chiama un metodo già testato?

7

Ho un metodo che fa qualcosa di simile

public void addFunds(Account account, int price) {
   int credits = account.getCredits()
   account.setCredits(credits + price)
   saveOrUpdate(account)
}

il metodo saveOrUpdate è già testato, quindi la mia domanda è: dovrei testare il metodo add funds ? Sto cercando di seguire le migliori pratiche.

    
posta Wissam Goghrod 01.10.2018 - 04:39
fonte

4 risposte

13

TL; DR

Pronuncia "dogmaticamente": Sì.

In pratica parlando: Dipende da te e dalla tua squadra. Se fossi nel tuo team, direi che i test sono preziosi , poiché aiutano a definire e applicare il contratto completo del metodo, incluso il suo comportamento (normale, edge-case e altro).

Se stavo scrivendo questo metodo:

Gli darei un FakeAccount e verifica che setCredits venga chiamato con il valore corretto. Ciò convalida sia che è il primo che ottiene il valore corrente che determina correttamente il nuovo valore. Metti alla prova i tuoi casi limite. Prova negativi. Prova Int.Max . Prova Int.Min . Ma scrivi i test come un consumatore - cosa, come chiamante, vuoi fare questa funzione in questi casi? Anche se il comportamento attuale corrisponde alle tue aspettative, definisce esplicitamente i comportamenti nella tua suite di test.

Farei dei test di integrazione. Creo un nuovo Account , addFunds() , cancella le cache, richiama l'account, asserisco il saldo, aggiungo di nuovo fondi, svuota la cache, recupera nuovamente e asserisco sul valore.

Proverei anche a pensare ad altri casi limite. Cosa succede se l'account non è valido in qualche modo? Forse come il tuo codice di test di scrittura ti rendi conto che non ha senso aggiungere fondi a un account senza nome o numero di conto - forse queste sono le assunzioni su cui dovresti fare affidamento. Forse voglio eccezioni significative per quelle cose.

Etc.

È interessante notare che se tu fossi TDD, è del tutto probabile che addFunds() verrebbe testato prima che esista anche saveOrUpdate() . I test per saveOrUpdate() verrebbero scritti una volta che alcuni test fallimentari del metodo esterno li avessero richiesti (come quelli per addFunds() ). Solo allora scrivi saveOrUpdate() .

Se non stai facendo TDD, scatto per copertura del 100% o preoccupato di fornire un codice pignolo, ciò che dovresti fare è interamente a tuo livello di comfort. O il livello di comfort della tua squadra. Se nessuno nella tua squadra vede valore nei test, è del tutto possibile che non aggiungano alcun valore.

Tuttavia, è anche del tutto possibile che saltare i test su un metodo come questo potrebbe costare alla tua compagnia milioni un giorno ...

    
risposta data 01.10.2018 - 06:45
fonte
8

IMHO stai facendo la domanda sbagliata. Il fatto che saveOrUpdate sia testato ovviamente non garantisce che la logica di calcolo in addFunds sia corretta. Quindi è abbastanza chiaro che la logica deve essere testata in qualche modo. Quindi la domanda che devi porre qui è come ottenere ciò?

  1. È necessario un test automatico o è sufficiente testare manualmente?

  2. Hai bisogno di un test di unità reale , per testare la logica di calcolo in isolamento, a parte saveOrUpdate ?

  3. E se la risposta a quest'ultimo è "sì", si dovrebbe scrivere un test aggiuntivo (integrazione) per addFund quindi?

Il punto 1 può essere risolto solo conoscendo il ciclo di vita del programma e se il programma o la funzione in gioco saranno soggetti a manutenzione per un periodo più lungo, forse anni. In questo caso, l'automazione del test vale in genere. (Ovviamente, importa anche se il tuo programma ha una GUI che consente il test manuale.)

Il punto 2 significa che uno deve refactoring il codice, mettendo la logica (senza l'operazione di salvataggio) in un metodo a sé stante. Se richiesto dipende dalla distinzione desiderata tra unità e test di integrazione nel sistema. La chiamata a saveOrUpdate può rallentare troppo la tua suite di test delle unità? È più semplice scrivere test di unità quando non è coinvolta nessuna chiamata a saveOrUpdate ? Questa sarebbe una strong indicazione per scrivere test di unità reali.

Il punto 3 dipende da quanto sforzo comporterà nel contesto del tuo sistema per impostare test stabili e riproducibili con un database coinvolto (che suppongo sia ciò che accade quando saveOrUpdate è chiamato), e se tali costi saranno bilanciato dai benefici di un test di integrazione automatizzato. In caso contrario, rendere il test dell'unità automatizzato e applicare manualmente il test di integrazione può essere perfettamente corretto.

    
risposta data 01.10.2018 - 07:48
fonte
3

Quando test (unità) addFunds , non dovresti verificare se saveOrUpdate funziona. Dovresti provare se saveOrUpdate viene chiamato (nelle giuste circostanze) e lasciarlo.

Se stai andando al test unitario, qualsiasi dipendenza inferiore (come il metodo saveOrUpdate ) dovrebbe essere derisa. Dopo tutto, stai solo provando a testare il metodo addFunds . Quello che stai suggerendo nella tua domanda è che tu collauda entrambi addFunds e saveOrUpdate , il che significa che non hai più unità test.

Non perdere mai traccia di ciò che stai testando .

Ogni volta che vuoi scrivere un test, prima chiediti cosa cerchi di dimostrare con i risultati del test . Se non riesci a pensare a qualcosa di significativo, non dovresti scrivere un test.

Non penso che sia necessario testare questo metodo. Così com'è, tutto ciò che riuscirai a testare sarà se l'orchestrazione dei metodi sottostanti ( getCredits , setCredits , saveOrUpdate ) viene chiamata come dovrebbe.

Ma questo test è superfluo. L'orchestrazione dei tre metodi è banalmente leggibile semplicemente guardando il codice. Il metodo non ha percorsi logici divergenti (ad esempio una struttura if else ) che fa sì che il flusso logico sia meno ovvio.

Alcuni controesempi di metodi che giustificano il test:

public void addFunds1(Account account, int price) {
    if(!account.IsLocked)
    {
        int credits = account.getCredits();
        account.setCredits(credits + positivePrice);
        saveOrUpdate(account);
    }
}

Qui c'è un test significativo: il metodo rifiuta correttamente di aggiornare gli account bloccati?

public void addFunds2(Account account, int price, Currency currency) {
    if(currency != account.Currency)
    {
         price = ConvertCurrency(currency, account.Currency, price);
    }

    int credits = account.getCredits();
    account.setCredits(credits + positivePrice);
    saveOrUpdate(account);
}

Qui c'è un test significativo: siamo in grado di aggiungere qualsiasi tipo di valuta a un account?

Prendi nota che siamo NON test:

  • Se la conversione di valuta è corretta.
  • Se il controllo di uguaglianza tra valute è implementato correttamente.
  • Se la logica di aggiornamento dell'account funziona.

Cosa testiamo ARE :

  • Se il metodo viene convertito nella valuta corretta quando la valuta price è diversa dalla valuta account .

public void addFunds3(Account account, int price) {
    bool shouldUpdate = false;        

    if(!account.IsLocked)
    {
        shouldUpdate = account.Currency.Code.StartsWith("Z");
    }
    else
    {
        int foo = account.AgeInDays + account.getCredits() % 97;
        string fooResult = externalRepo.CalculateResult(foo);
        shouldUpdate = foo.Length > 3;
    }

    if(shouldUpdate)
    {
        int credits = account.getCredits();
        account.setCredits(credits + price);
        saveOrUpdate(account);
    }
}

So che questo è un esempio sciocco, ma è inteso come un esempio di logica complessa e non del tutto ovvia. Ci sono molte cose valide da testare qui. Un'intenzione di test generalizzata potrebbe essere descritta come:

Poiché ci sono motivi per aggiornare l'account solo in determinate situazioni, il metodo aggiorna correttamente l'account in tutte le circostanze necessarie in cui è richiesto un aggiornamento e non aggiorna l'account in tutte le circostanze necessarie in cui un aggiornamento è espressamente proibito? (saranno molti test diversi)

    
risposta data 01.10.2018 - 08:54
fonte
0

IMHO, se saveOrUpdate è stato testato non ha nulla a che fare con il test addFunds . Normalmente, quando provi addFunds , prendi in giro saveOrUpdate e controlla se è chiamato con argomenti corretti.

Quindi sì, dovresti testarlo.

    
risposta data 05.10.2018 - 04:41
fonte

Leggi altre domande sui tag