2013-07-16 17 views
5

Ho un'origine dati da cui posso richiedere un elenco di persone che vivono in un paese (qualsiasi) e un metodo che recupera le persone da tale origine dati e le ordina in base al loro nome in ordine alfabetico. Come dovrei scrivere il mio test unitario per assicurarmi che la parte di ordinamento del mio metodo funzioni correttamente?Come si scrive un test unitario per verificare che una funzione elabori il suo risultato?

Questo è ciò che il mio SUT assomiglia:

class PeopleStuff { 

    public IData data; 

    public List<Person> getSortedPeopleForCountry(String countryName) { 
     List<Person> people = data.getPeopleForCountry(countryName); 

     Comparator nameComparator = new PersonNameComparator(); 
     Collections.sort(people, nameComparator); 

     return people; 
    } 

} 

E questo è ciò che il mio test di unità si presenta come:

@Test public void testGetPeopleSortsByPeopleName() { 
    String COUNTRY = "Whatistan"; 

    // set up test (the 3 lines below are actually in a @Before setup method) 
    PeopleStuff peopleStuff = new PeopleStuff(); 
    IData mockData = createNiceMock(IData.class); 
    peopleStuff.data = mockData; 

    // set up data 
    List<PersonName> mockPeopleList = new ArrayList<PersonName>(); 
    mockPeopleList.add(new Person(COUNTRY, "A")); 
    mockPeopleList.add(new Person(COUNTRY, "D")); 
    mockPeopleList.add(new Person(COUNTRY, "B")); 
    mockPeopleList.add(new Person(COUNTRY, "C")); 

    when(mockData.getPeopleForCountry(COUNTRY)).thenReturn(mockPeopleList); 

    // exercise 
    List<String> result = peopleStuff.getSortedPeopleForCountry(COUNTRY); 

    // assert 
    assertEquals("A", result.get(0).name); 
    assertEquals("B", result.get(1).name); 
    assertEquals("C", result.get(2).name); 
    assertEquals("D", result.get(3).name); 
} 

Che cosa ho bisogno di sapere è se il modo in cui mi sto spegnendo i dati , eseguendo il test e rendendo le asserzioni corrette, o se ci sono modi migliori per farlo.

La mia applicazione ha molti metodi per testare e molti algoritmi di ordinamento personalizzati; Ho implementato tutti i test per utilizzare 4 valori che ho mozzato così, in a "random" order che scelgo quando scrivo il test.


Devo testare solo se vengono chiamati i comparatori? Non mi sembra giusto, perché non so se vengono chiamati i dati giusti o al momento giusto nell'algoritmo che si trova all'interno di getSortedPeopleForCountry(). Voglio rilevare situazioni come questa:

public List<Person> getSortedPeopleForCountry(String countryName) { 
    List<Person> people = data.getPeopleForCountry(countryName); 

    Comparator nameComparator = new PersonNameComparator(); 
    List<Person> sortedPeople = new ArrayList<Person>(people) 
    Collections.sort(sortedPeople, nameComparator); 

    return people; // oops! 
} 

Devo lasciare in questo modo e aggiungere comparatori finte che utilizzano i veri comparatori ma anche verificano che stanno chiamati?

Sto facendo bene?

+0

Vorrei ordinare l'elenco e quindi iniziare a confrontare i suoi elementi in coppie per assicurarmi che l'elemento * current * abbia lo stesso o un * più grande * paese del precedente. –

+0

@LuiggiMendoza L'ho già fatto, ma ho cambiato idea. Ciò ha aggiunto una dipendenza a 'PersonNameComparator' all'interno del test. E ci sono voluti un ciclo 'for' di 3 linee, il che significa un algoritmo in più nel test che un lettore dovrebbe capire per capire il test. –

+0

Fai sembrare che 3 linee di codice siano piuttosto difficili da capire ... Infatti, dato che non lavoro con easymock, tutto il codice di cui sopra è molto più difficile da capire di un semplice ciclo 'for' con un 'if'. –

risposta

2

Penso che il tuo test corrente sia molto buono - i test sono realistici, esercitano tutto il codice e stai prendendo in giro l'origine dati & utilizzando l'iniezione di dipendenza per fornire un'origine dati fittizia. C'è un sacco di buone pratiche in corso in questo test.

Sulla questione se si dovrebbe cercare di prendere in giro i comparatori (e quindi rendere il test su testGetPeopleSortsByPeopleName un test di unità pura), sarà sicuramente ottenere due opinioni diverse qui:

  • un purista sosterrebbe che il test è tecnicamente un test di integrazione e, per avere i test di unità adeguati, è necessario regolare il test per utilizzare un comparatore di simulazione e quindi testare separatamente il comparatore.
  • Un pragmatico sosterrebbe che il test è già di alta qualità e che non importa che non sia un test unitario nel senso più stretto. Inoltre, dividere questo in due test di unità separati può rendere il test meno leggibile - cosa che immagino sarebbe il caso del test di cui sopra se si trattasse di comparare simulatori.

La mia opinione personale è che si dovrebbe lasciare così com'è, il fatto che si dispone di una elevata qualità, prova leggibile che esercita tutto il codice e afferma in modo efficace le vostre esigenze è molto più importante di preoccuparsi di avere rigorosamente pura test unitari.

L'unico modo in cui il test sembra aver bisogno di miglioramenti è la lunghezza del metodo di test: penso che un piccolo metodo di estrazione potrebbe aiutare a migliorare la leggibilità e rendere il metodo di test più espressivo. Vorrei puntare a qualcosa di simile:

@Test public void testGetPeopleSortsByPeopleName() { 

    peopleStuff.data = buildMockDataSource(COUNTRY, "A", "D", "B", "C") 

    List<String> result = peopleStuff.getSortedPeopleForCountry(COUNTRY); 

    assertPersonList(result, "A", "B", "C", "D") 
} 

private IData buildMockDataSource(String country, String ... names) { 
    ... 
} 

private void assertPersonList(List<Person> people, String ... names) { 
    ... 
} 
+0

Ok, quindi sono andato con questo e ho finito con un sacco di metodi di generazione degli stub e ho elencato i metodi di asserzione, ma è andato tutto bene perché li ho appena messi tutti in un file di test helper. I test sembrano molto accurati e facili da mantenere. Grazie. –

1

Separare la logica di ordinamento dalla restituzione dell'elenco. Quindi avrei getPeopleForCountry (String countryName) restituire solo una lista mentre una lista ordinata sarebbe stata restituita da getSortedPeopleForCountry (List). In questo modo puoi testare come funziona prima e dopo l'ordinamento. Inoltre, potresti voler sovrascrivere il metodo Equals() per confrontare i nomi se è quello con cui vuoi andare, ma in seguito vorrai confrontarti con altre proprietà. Questa è la tua chiamata.

+0

Questo è molto vago e ignora completamente che ho scritto che ho comparatori personalizzati per gli oggetti Person. Inoltre, questo codice è solo una versione dumbed di ciò che ho in sviluppo. La domanda è come testare che una funzione _sembra come_ l'esempio che ho scritto è ordinare i dati dati. –

+0

Come si ignora il comparatore che hai scritto? Il tuo comparatore verrebbe utilizzato all'interno di getSortedPeopleForCountry (Elenco T) ... dalla mia risposta. Ad ogni modo, questo è il mio modo di interpretare il tuo codice. Se avessi un metodo di prova come testGetPeopleForCountryWhenNotSorting(), potresti testare che l'altro metodo di ordinamento non testerebbe. – Mukus

0
ObjectA[] arr = objectAList.toArray(new ObjectA[objectAList.size()]); 
for (int i = 0; i < objectAList.size() - 1; i++) { 
     int j = i + 1; 
     assertTrue(arr[i].getDate().compareTo(arr[j].getDate()) >= 0); 
} 

Questo Codice rappresenta un esempio in cui gli oggetti è ordinato per data campo in ordine decrescente ArrayList contaning Objecta. Stiamo verificando se il membro della lista ha una data inferiore o uguale rispetto al suo predecessore.

Problemi correlati