2016-11-18 2 views
0

Ich bin gerade dabei, einige Komponententests für meinen Dienst in Go zu erstellen, sowie andere Funktionen, die auf dieser Funktionalität aufbauen, und ich frage mich, was ist der beste Weg zum Komponententest das in Go? Mein Code sieht so aus:Komponententest in Golang

type BBPeripheral struct { 
    client *http.Client 
    endpoint string 
} 

type BBQuery struct { 
    Name string `json:"name"` 
} 

type BBResponse struct { 
    Brand   string `json:"brand"` 
    Model   string `json:"model"` 
    ... 
} 

type Peripheral struct { 
    Brand   string 
    Model   string 
    ... 
} 

type Service interface { 
    Get(name string) (*Peripheral, error) 
} 

func NewBBPeripheral(config *peripheralConfig) (*BBPeripheral, error) { 
    transport, err := setTransport(config) 
    if err != nil { 
     return nil, err 
    } 

    BB := &BBPeripheral{ 
     client: &http.Client{Transport: transport}, 
     endpoint: config.Endpoint[0], 
    } 

    return BB, nil 
} 


func (this *BBPeripheral) Get(name string) (*Peripheral, error) { 

    data, err := json.Marshal(BBQuery{Name: name}) 
    if err != nil { 
     return nil, fmt.Errorf("BBPeripheral.Get Marshal: %s", err) 
    } 

    resp, err := this.client.Post(this.endpoint, "application/json", bytes.NewBuffer(data)) 
    if resp != nil { 
     defer resp.Body.Close() 
    } 
    if err != nil { 
     return nil, err 
    } 
    if resp.StatusCode != http.StatusOK { 
     return nil, fmt.Errorf(resp.StatusCode) 
    } 

    var BBResponse BBResponse 

    body, err := ioutil.ReadAll(resp.Body) 
    if err != nil { 
     return nil, err 
    } 

    err = json.Unmarshal(body, &BBResponse) 
    if err != nil { 
     return nil, err 
    } 

    peripheral := &Peripheral{} 

    peripheral.Model = BBResponse.Model 
    if peripheral.Model == "" { 
     peripheral.Model = NA 
    } 

    peripheral.Brand = BBResponse.Brand 
    if peripheral.Brand == "" { 
     peripheral.Brand = NA 
    } 

    return peripheral, nil 
} 

ist der effizienteste Weg, um diesen Code zu testen und den Code, der diese Funktionen verwendet eine separate goroutine spin up wie der Server zu fungieren, verwenden http.httptest Paket, oder etwas anderes? das ist das erste Mal, dass ich versuche, einen Test zu schreiben, dann weiß ich nicht wirklich wie.

+2

Go verfügt über eigene Testwerkzeuge. Sehen Sie hier https://golang.org/pkg/testing/ ... Wenn Sie auf Github herumspielen, um andere gut genutzte Go-Pakete zu sehen, werden Sie oft Dateien finden, die mit _test.go enden. Diese Dateien sind für Komponententests, aber unter Verwendung des Cmd-Go-Tests und unter Verwendung des Testpakets. Auch das von Ihnen erwähnte Paket ist ein guter Anfang. Nach dem Test, da dies ein Server ist, würde ich wahrscheinlich einen Belagerungstest durchführen, um den Server zu belasten, um zu sehen, wie er mit https://www.joedog.org/siege-home/ umgehen kann. – reticentroot

Antwort

1

Es kommt wirklich völlig darauf an. Go bietet so ziemlich alle Tools, die Sie zum Testen Ihrer Anwendung auf jedem einzelnen Level benötigen.

Einheit Tests

Entwurf wichtig ist, weil es nicht viele Tricks sind dynamisch Objekte Mock/Stub bereitzustellen. Sie können Variablen für Tests überschreiben, jedoch werden alle Arten von Problemen mit der Bereinigung aufgehoben. Ich würde mich auf IO-freie Komponententests konzentrieren, um zu überprüfen, ob Ihre spezifische Logik funktioniert.

Zum Beispiel können Sie BBPeripheral.Get Methode testen, indem Sie client eine Schnittstelle, die es während Instanziierung erfordert, und einen Stub für den Test bereitstellen.

func Test_BBPeripheral_Get_Success(*testing.T) { 
    bb := BBPeripheral{client: &StubSuccessClient, ...} 
    p, err := bb.Get(...) 
    if err != nil { 
    t.Fail() 
    } 
} 

Dann könnten Sie einen Stub Fehler-Client erstellen, die Fehlerbehandlung in der Get Methode Übungen:

func Test_BBPeripheral_Get_Success(*testing.T) { 
    bb := BBPeripheral{client: &StubErrClient, ...} 
    _, err := bb.Get(...) 
    if err == nil { 
    t.Fail() 
    } 
} 

Komponente/Integrationstests

Diese Tests Übung, die jede einzelne Einheit kann helfen in Ihrem Paket können zusammen im Einklang arbeiten. Da Ihr Code über http spricht, bietet Go das Paket httptest, das verwendet werden könnte.

Um dies zu tun, könnte der Test einen httptest-Server mit einem Handler erstellen, der registriert ist, um die Antwort zu liefern, die this.endpoint erwartet. Sie könnten dann Ihren Code über die öffentliche Schnittstelle ausführen, indem Sie eine NewBBPeripheral anfordern, die this.endpoint entspricht und der Eigenschaft Server.URL entspricht.

Damit können Sie Ihren Code simulieren und mit einem echten Server sprechen.

gehen Stück-

Go macht es so einfach gleichzeitige Code zu schreiben, und macht es so einfach, es zu testen. Das Testen des Codes der obersten Ebene, der eine Go-Routine hervorbringt, die NewBBPeripheral ausübt, könnte dem obigen Test sehr ähnlich sein. Zusätzlich zum Starten eines Testservers muss Ihr Test warten, bis Ihr asynchroner Code abgeschlossen ist. Wenn Sie keine Möglichkeit haben, den Dienst abzubrechen/abzuschalten/Signal vollständig zu machen, müssen Sie möglicherweise einen Test mit Go-Routinen durchführen.

Race Condition/Load Testing

in bechmark Test mit -race Flagge kombiniert gebaut des Verwenden von unterwegs, können Sie Ihren Code leicht ausüben können, und es für Rennbedingungen profilieren, die Tests nutzen Sie oben geschrieben habe.


Eine Sache im Auge zu behalten, wenn die Umsetzung Ihrer Anwendung noch im Fluss ist, Unit-Tests schreiben kann eine große Menge an Zeit kosten. Durch die Erstellung mehrerer Tests, die die öffentliche Schnittstelle Ihres Codes darstellen, können Sie leicht überprüfen, ob Ihre Anwendung funktioniert, und gleichzeitig die Implementierung ändern.