Evita FileUtil creato per i test [chiuso]

0

Creo costantemente classi util come File per poter simulare la funzionalità dei file nei test.

È conveniente ma viola l'idea di base - non modificare il codice di produzione per conformarsi ai test. Potrei anche preparare la directory di test con i file di test, ma suona anche come test dell'unità non corretto.

C'è un buon approccio su come affrontare questo problema?

UPD

Ecco un esempio che illustra l'approccio:

public class FileUtil {
    public File[] listFiles(String pathToFolder) {
        return new File(pathToFolder).listfiles();
    }
}

public class CSVImporter {
    ...
    public CSVImporter(FileUtil files) {
       ...
    }
    ...
    public void import(String pathToFolder) {
        File[] files = files.listfiles(pathToFolder);
        ...
    }
}
    
posta Eugen Martynov 26.06.2015 - 07:49
fonte

2 risposte

2

Modificare il codice per poterlo verificare non ha nulla di sbagliato. In effetti, uno dei punti di TDD e dei test unitari in generale è di incoraggiarti a scrivere un codice più gestibile.

D'altro canto, il tuo esempio illustra i test di integrazione, di sistema o funzionali, non i test di unità. Nei test unitari, i test sono il più possibile indipendenti dall'ambiente, il che, nel tuo caso, significa che non ci si aspetta che crei una directory di test con i file di test al suo interno ai fini del test dell'unità (a meno che il tuo test dell'unità non si concentri specificamente su una classe che legge i file).

Hai già fatto il primo passo dell'introduzione di Dependency Injection in CSVImporter quando si tratta di FileUtil , e questo è ottimo. Il prossimo passo è creare uno stub FileUtilStub che implementa l'interfaccia IFileUtil , ma non fa nulla con i file reali: restituisce semplicemente i dati demo. Ad esempio, quando elenchi i file, potrebbe restituire ["file1.txt", "file2.txt"] e, durante la lettura di qualsiasi file, potrebbe restituire Hello,World .

Ora vengono i casi limite. Dato che stai testando materiale CSV, cosa succede se crei uno stub% diversoFileUtilEmptyFileStub che restituisce una stringa vuota quando richiesto per caricare un file? Un FileUtilEmptyListStub può restituire una lista vuota di file. Altri possono restituire file molto lunghi o file con caratteri Unicode, ecc., Per sapere come la classe gestisce tali casi.

Un ulteriore refactoring può consistere nella creazione di uno stub che prende come parametro un elenco di file e contenuti di file. Ciò rende possibile scrivere meno codice mentre si inserisce tutto il codice pertinente all'interno del corpo del test dell'unità stessa:

public void TestEmptyList()
{
    var stub = new FileUtilStub([], "hello,world");
    var importer = new CSVImporter(stub);
    // Do something with the importer and assert.
}

public void TestListWithNewlineInNames()
{
    var stub = new FileUtilStub(["file\n.txt"], "hello,world");
    var importer = new CSVImporter(stub);
    // Do something with the importer and assert.
}

...
    
risposta data 26.06.2015 - 09:58
fonte
1

Innanzitutto, non c'è nulla di sbagliato nella modifica del codice di produzione se diventa più verificabile in questo modo.

Ciò che chiedi dipende da come appare il tuo codice di produzione e da come tratta i file. Se apre solo un file, funziona con il flusso di file e chiude di nuovo il file, separa la parte "Apri / Chiudi file" e implementa la parte "core" rimanente in termini di flussi. In questo modo, puoi sostituire il flusso di file con un flusso di memoria a scopo di test e creare quel flusso di memoria "al volo" nei test di unità.

Alla tua modifica: da qualche parte nella tua classe CSVImporter c'è un metodo come

  void importFile(File file){
      FileStreamReader fsr = new FileStreamReader(file);
      // do something with fsr
  }

Rif. la parte do something with fsr in una funzione con solo InputStreamReader come parametro.

void importFile(File file){
     FileStreamReader fsr = new FileStreamReader(file);
     importStream(fsr);
}
void importStream(InputStreamReader isr)
{
    // here is the core logic, which is useful to be tested in a unit test
}

Ora rendi pubblico questo metodo o almeno solo il pacchetto privato e provalo fornendo un InputStreamReader con i dati dalla memoria:

 // somewhere in your unit test:      
 isr = new InputStreamReader(new ByteArrayInputStream(...)) ;
 csvImporter.importStream(isr);

(e per testare la logica di elaborazione dei file, non creare test unitari - crea invece test di integrazione automatici separati, utilizzando alcuni file reali).

    
risposta data 26.06.2015 - 08:54
fonte

Leggi altre domande sui tag