Codice verificabile dell'unità: visibilità del metodo rispetto alla complessità del test

6

Non riesco a decidere come reimpostare il codice giusto. Diciamo che ho un pezzo ipotetico logico complesso:

public class ImageService
{
     public void UploadImage(VectorData data) {
         var image = ConvertVectorDataToImage();
         var thumbnail = CreateThumbnail(image);
         SaveThumbnail(thumbnail);
         SaveImage(image);
         SendEmail(image);
         ...
     }
}

(Se qualcosa nell'esempio è fuori dalla singola responsabilità, facciamo finta di poter fare un esempio migliore)

Se faccio visualizzare UploadImage (pubblico), i test di scrittura diventano complicati. Tendono ad essere lunghi, difficili da leggere e, se si desidera evitare la duplicazione del codice, viene visualizzata la logica dei test.

Se faccio vedere tutti quei piccoli pezzi visibili, l'API diventa caotica (perché nel mio esempio, l'unica cosa interessante per tutti è il metodo UploadImage). Ancora peggio, dopo un po 'di tempo le persone tenderanno a usare quei piccoli metodi, perché sono pubblici, non perché dovrebbero essere usati al di fuori della classe.

Quindi la mia domanda è: come si bilancia tra visibilità e complessità del test? O sto facendo qualcosa di sbagliato al primo posto?

    
posta Giedrius 20.04.2011 - 12:17
fonte

3 risposte

5

Per prima cosa devi mantenere che dovresti favorire la composizione sull'ereditarietà. Ciò significa che, invece di cercare di evitare la duplicazione del codice per sottoclasse, dovrai comporre il comportamento da un insieme di classi che implementano questo comportamento.

Non ti devi preoccupare della visibilità di tutte quelle classi, poiché le interfacce saranno l'unica API visibile i clienti vedranno.

Se altri sviluppatori riutilizzano parte del codice, non è solo una buona cosa? Ciò significa che sei riuscito a creare blocchi predefiniti riutilizzabili.

    
risposta data 20.04.2011 - 13:10
fonte
2

Dovresti iniziare a utilizzare un quadro di simulazione e il codice alle interfacce .

Utilizza le interfacce atomiche che descrivono le attività che desideri eseguire il più possibile utilizzando SRP:

IImageConvertor { ConvertVectorDataToImage }
IThumbnailWorker { CreateThumbnail; SaveThumbnail }

eccetera

Ora la tua classe che esegue il caricamento dell'immagine dovrebbe disporre di membri dati per ciascuna di queste interfacce:

public class ImageService
{
    IImageConvertor _imageConvertor;
    IThumbnailWorker _thumbnailWorker;
}

e poi nel tuo metodo che chiami

public void UploadImage(VectorData data) {
     var image = _imageConvertor.ConvertVectorDataToImage();
     var thumbnail = _thumbnailWorker.CreateThumbnail(image);
     _thumbnailWorker.SaveThumbnail(thumbnail);
     ...
 }

Ora il tuo framework di derisione prende il sopravvento, quindi, durante i test, crei oggetti mock per le tue interfacce e i tuoi test si limitano a verificare che queste interfacce abbiano i metodi corretti chiamati e che vengano chiamati nell'ordine corretto. In realtà non esegui alcuna manipolazione di immagini o alcun accesso ai file. Ciò mantiene i tuoi test veloci e aiuta davvero a mantenere il tuo codice disaccoppiato e modulare.

Puoi testare gli oggetti che sono alla base di ciascuna di queste interfacce separatamente. In generale, le persone non testano cose come l'accesso ai file, perché generalmente sono gestite dal linguaggio o da API di terze parti, tutto ciò che si sta facendo è il wrapping e tutti i bug vengono rilevati abbastanza rapidamente durante il test delle unità. Se pensi che sia una buona idea o meno è un'altra questione.

    
risposta data 20.04.2011 - 15:09
fonte
0
src/main/java/net.bobah/example/MyClass.java:
public class MyClass {
  void defaultMethod() { ... } // visible only to classes from the same package
}

src/main/java/net.bobah/example/MyClassTest.java:
public class MyClassTest {
  @Test
  void defaultMethodTest() { ... testInst.defaultMethod(); ... } // works fine
}
    
risposta data 20.04.2011 - 12:29
fonte

Leggi altre domande sui tag