2009-07-04 18 views
5

Sono un principiante del test delle unità e sto seguendo alcuni consigli sulle migliori pratiche. Sto codificando in Cocoa usando Xcode.File di dati esterni per i test delle unità

Ho un metodo che convalida un URL inserito da un utente. Voglio che accetti solo il protocollo http: // e accetti solo URL con caratteri validi.

È accettabile un test per questo e utilizzare un file di dati di test? Il file di dati fornisce esempi di URL validi/non validi e se l'URL debba o meno essere convalidato. Sto anche usando questo per controllare la descrizione e il dominio del messaggio di errore.

Perché sto facendo questo

Ho letto Pragmatic Unit Testing in Java con JUnit e questo dà un esempio con un file di dati esterni, che mi fa pensare questo è OK. Inoltre significa che non ho bisogno di scrivere molti test unitari con codice molto simile solo per testare dati diversi.

Ma d'altra parte ...

Se sto testando per:

  • caratteri non validi
  • e un protocollo non valido
  • e URL validi

tutti nello stesso file di dati di test (e quindi nello stesso test) mi causeranno problemi in seguito? Ho letto che un test dovrebbe fallire solo per una ragione.

È quello che sto facendo OK?

Come fanno le altre persone a utilizzare i dati di test nei loro test unitari, se non del tutto?

risposta

5

In generale, utilizzare un file di dati di test solo quando è necessario. Esistono numerosi svantaggi nell'utilizzo di un file di dati di test:

  • Il codice per il test è suddiviso tra il codice di test e il file di dati di test. Ciò rende il test più difficile da comprendere e mantenere.
  • Si desidera mantenere i test dell'unità il più velocemente possibile. Avere test che leggono inutilmente file di dati può rallentare i test.

Ci sono alcuni casi in cui mi faccio uso di file di dati:

  • L'ingresso è di grandi dimensioni (ad esempio, un documento XML). Sebbene sia possibile utilizzare la concatenazione di stringhe per creare un input di grandi dimensioni, può rendere difficile la lettura del codice di test.
  • Il test sta effettivamente testando il codice che legge un file. Anche in questo caso, è possibile che si desideri che il test scriva un file di esempio in una directory temporanea in modo che tutto il codice per il test si trovi in ​​un'unica posizione.

Invece di codificare gli URL validi e non validi nel file, suggerisco di scrivere i test nel codice.Suggerisco di creare un test per i caratteri non validi, un test per i protocolli non validi, un test per i domini non validi e un test per un URL valido. Se non ritieni di avere una copertura sufficiente, puoi creare un mini test di integrazione per testare più URL validi e non validi. Ecco un esempio in Java e JUnit:

public void testManyValidUrls() { 
    UrlValidator validator = new UrlValidator(); 
    assertValidUrl(validator, "http://foo.com"); 
    assertValidUrl(validator, "http://foo.com/home"); 
    // more asserts here 
} 

private static void assertValidUrl(UrlValidator validator, String url) { 
    assertTrue(url + " should be considered valid", validator.isValid(url); 
} 
+0

Porca vacca. È incredibilmente utile. Questo è esattamente il tipo di consiglio che stavo cercando. Mi sentivo un po 'strano scrivere così tanto dei miei dati di convalida in un file esterno, ma non riuscivo a capire il perché. La tua risposta inchioda il mio brutto presentimento: fa male alla manutenibilità e alla velocità. Il tuo codice di esempio è anche molto utile come punto di partenza per il mio codice. Grazie. È fantastico. –

1

Mentre penso che questa è una domanda perfettamente ragionevole chiedere, non credo che si dovrebbe essere eccessivamente preoccupati per questo. A rigor di termini, hai ragione sul fatto che ogni test dovrebbe testare solo una cosa, ma ciò non preclude l'utilizzo di un file di dati.

Se il sistema in prova (SUT) è un semplice parser/validatore di URL, presumo che occorra un singolo URL come parametro. Pertanto, esiste un limite alla quantità di dati invalidi che è possibile inserire contemporaneamente. Anche se si alimenta un URL che contiene sia caratteri non validi, sia un protocollo non valido, ciò causerebbe solo un singolo risultato (che l'URL non era valido).

Quello che stai descrivendo è un test guidato dai dati (chiamato anche test parametrizzato). Se si mantiene il test in sé semplice, alimentarlo con dati diversi non è di per sé problematico.

Ciò che si do do è che si desidera essere in grado di individuare rapidamente perché un test non riesce quando/se ciò accade alcuni mesi da ora. Se l'output del test punta a una riga specifica nel file di dati di test, dovresti essere in grado di capire rapidamente cosa è andato storto. D'altra parte, se l'unico messaggio che si ottiene è che il test ha avuto esito negativo e una qualsiasi delle righe nel file potrebbe essere in errore, si inizierà a vedere i contorni di un incubo di manutenibilità del test.

Personalmente, mi sporgo leggermente per avere i dati di test il più vicino possibile ai test. Questo perché considero molto importante il concetto di test come specifiche eseguibili. Quando i dati del test sono hard-coded all'interno di ciascun test, possono chiaramente specificare la relazione tra input e output atteso. Più rimuovi i dati dal test stesso, più diventa difficile leggere questa "specifica".

Ciò significa che tendo a definire i valori dei dati di input all'interno di ciascun test. Se devo scrivere un sacco di test molto simili in cui l'unica variazione è l'input e/o l'output atteso, scrivo un test parametrizzato, ma invoco ancora quel test parametrizzato da test hard-coded (che ognuno è solo una singola riga di codice). Non penso di aver mai usato un file di dati esterno.

Ma poi di nuovo, in questi giorni, non so nemmeno conoscere quale è il mio input, poiché utilizzo Constrained Non-Determinism. Invece, lavoro con Equivalence Classes e Derived Values.

+0

Una risposta davvero utile. È interessante che tu sia un po 'più clemente dei file di dati rispetto alla risposta accettata. La tua risposta è buona per darmi una più ampia gamma di opinioni - come con tutto, così tanto è giù per l'opinione e il giudizio, ma insieme con la risposta accettata, ho alcuni ottimi punti di partenza per prendere la mia decisione informata. Molte grazie! –

Problemi correlati