Il modo migliore per scrivere i test delle unità per il middleware HTTP

2

Sto utilizzando questa libreria go ( link ) per creare un'app server proxy personalizzata. L'app utilizza diversi middleware del seguente modulo:

MyMiddlewarFunc(ctx *goproxy.ProxyCtx) goproxy.Next {
    if ctx.Req.Header.Get("If-None-Match") == "test"{
       //do something
    }
}

Ora sto provando a scrivere test unitari per queste funzioni middleware. Ecco due possibili diversi approcci che ho potuto trovare:

  1. Scrivi funzioni di test per chiamare questi middlware con instnace personalizzato 'goproxy.ProxyCtx' e inserendo i dati fittizi richiesti in quella struttura. Questo dovrebbe assomigliare a:

    func TestMyMiddlewarFunc() { ctx = &goproxy.ProxyCtx{} ctx.Req.Header.Set("If-None-Match", "test") ctx.Req.Header.Set("If-Modified-Since", "test") MyMiddlewarFunc(ctx) //verify if changes are done according to logic }

    Professionisti: questo approccio sembra funzionare per la maggior parte dei casi, semplice da scrivere. Contro: ha un problema: dato che la struttura dati ctx proviene da una terza parte, a volte sarebbe difficile sapere quale tipo di dati è necessario impostare al suo interno per attivare / eseguire qualcosa correttamente. Ad esempio, all'interno di un middleware, ho una chiamata al metodo 'ctx.DispatchResponseHandlers', ma genera un errore di runtime, molto probabilmente a causa di qualcosa non impostato correttamente durante il passaggio dell'istanza.

  2. Crea un server http di test, gestisci il middleware e invia una richiesta personalizzata che attiva il meccanismo nel middleware e quindi verifica la risposta / internal per vedere se ci sono cambiamenti.

     func TestMyMiddlewarFunc() {
    
     proxyServer := goproxy.NewProxyHttpServer() 
     proxyServer.HandleFunc(MyMiddlewarFunc)   
     s := httptest.NewServer(proxyServer)
    
     client := &http.Client{}
    
     req, _ := http.NewRequest("GET", s.URL+"/foo", nil)
     req.Header.Set("Origin", "foo")
     resp, err := client.Do(req)
    
     //verify resp
     }
    

    Professionisti: questo secondo approccio sembra gestire il problema affrontato nell'approccio precedente. Contro:

    • ha un po 'più di overheads per l'installazione.
    • Dato che ci sono diversi middleware e dipendenze diversi tra loro, è necessario creare diversi metodi di simulazione per gestire tali dipendenze, il che rende la struttura più complessa.
    • Inoltre, il suo tipo di avere il test di integrazione sapore, ma anche se in realtà suppone di essere unit test.

Quindi, sono curioso di sapere quale approccio sceglieresti e perché? Alcuni dettagli a supporto della tua scelta sarebbero grandiosi.

    
posta Rana 04.12.2015 - 07:20
fonte

1 risposta

1

Né il n. 1 né il n. 2 ti darebbero dei test unitari, secondo me. Anche se non esiste una distinzione oggettiva tra test di unità e test di integrazione, un test che copra il codice che possiedi e un codice che non possiedi sarebbe probabilmente considerato un'integrazione il più delle volte.

Poiché Go supporta le funzioni di prima classe, il modo più semplice per convertire il tuo esempio in supporto dei test di unità reali sarebbe quello di cambiare questo:

MyMiddlewarFunc(ctx *goproxy.ProxyCtx) goproxy.Next {
    if ctx.Req.Header.Get("If-None-Match") == "test"{
       //do something
    }
}

per qualcosa di più simile a questo:

MyMiddlewarFunc(ctx *goproxy.ProxyCtx, doSomething func()) goproxy.Next {
    if ctx.Req.Header.Get("If-None-Match") == "test"{
       doSomething();
    }
}

Ora puoi facilmente scrivere un test su qualunque funzione tu passi per doSomething che non ha bisogno di sapere nulla su goproxy. Probabilmente sarebbe un test unitario reale (supponendo che doSomething() sia abbastanza semplice).

Questo non vuol dire che i due tipi di test di integrazione che descrivi non siano desiderabili. In effetti, dovresti averne alcuni. Ma dovresti mirare ad avere molti più test unitari rispetto ai test di integrazione, poiché i test unitari tendono a scalare meglio e ad essere meno fragili. Se i tuoi test di integrazione dovrebbero essere di tipo 1 o 2, sono d'accordo con il commento di Robert: Usa 1 quando 1 funziona e 2 quando 2 funziona.

    
risposta data 04.12.2015 - 11:31
fonte

Leggi altre domande sui tag