Unit-Tests für die Funktionen, die die Nutzung gorilla/mux: URL-Parameter

Hier ist, was ich versuche zu tun :

main.gehen

package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
)

func main() {
    mainRouter := mux.NewRouter().StrictSlash(true)
    mainRouter.HandleFunc("/test/{mystring}", GetRequest).Name("/test/{mystring}").Methods("GET")
    http.Handle("/", mainRouter)

    err := http.ListenAndServe(":8080", mainRouter)
    if err != nil {
        fmt.Println("Something is wrong : " + err.Error())
    }
}

func GetRequest(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    myString := vars["mystring"]

    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "text/plain")
    w.Write([]byte(myString))
}

Dies schafft eine grundlegende http-server lauscht auf port 8080, dass Echos, die URL-parameter in den Weg. Also für http://localhost:8080/test/abcd schreibt er wieder eine Antwort, die mit abcd im response-body.

Den unit-test für die GetRequest() Funktion ist in main_test.gehen :

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/gorilla/context"
    "github.com/stretchr/testify/assert"
)

func TestGetRequest(t *testing.T) {
    t.Parallel()

    r, _ := http.NewRequest("GET", "/test/abcd", nil)
    w := httptest.NewRecorder()

    //Hack to try to fake gorilla/mux vars
    vars := map[string]string{
        "mystring": "abcd",
    }
    context.Set(r, 0, vars)

    GetRequest(w, r)

    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, []byte("abcd"), w.Body.Bytes())
}

Das test-Ergebnis :

--- FAIL: TestGetRequest (0.00s)
    assertions.go:203: 

    Error Trace:    main_test.go:27

    Error:      Not equal: []byte{0x61, 0x62, 0x63, 0x64} (expected)
                    != []byte(nil) (actual)

            Diff:
            --- Expected
            +++ Actual
            @@ -1,4 +1,2 @@
            -([]uint8) (len=4 cap=8) {
            - 00000000  61 62 63 64                                       |abcd|
            - }
            +([]uint8) <nil>


FAIL
FAIL    command-line-arguments  0.045s

Die Frage ist, wie kann ich fake die mux.Vars(r) für die unit-tests?
Ich habe festgestellt, dass einige Diskussionen hier aber die vorgeschlagene Lösung funktioniert nicht mehr. Die vorgeschlagene Lösung war :

func buildRequest(method string, url string, doctype uint32, docid uint32) *http.Request {
    req, _ := http.NewRequest(method, url, nil)
    req.ParseForm()
    var vars = map[string]string{
        "doctype": strconv.FormatUint(uint64(doctype), 10),
        "docid":   strconv.FormatUint(uint64(docid), 10),
    }
    context.DefaultContext.Set(req, mux.ContextKey(0), vars) //mux.ContextKey exported
    return req
}

Diese Lösung funktioniert nicht, weil context.DefaultContext und mux.ContextKey nicht mehr existieren.

Anderen vorgeschlagenen Lösung wäre, ändern Sie Ihren code so, dass die Anfrage-Funktionen akzeptieren auch ein map[string]string als Dritten parameter. Andere Lösungen sind eigentlich ab einem server und bauen Sie die Anfrage und senden Sie es direkt an den server. Meiner Meinung nach würde dies die Niederlage der Zweck von unit-Tests, die sich im wesentlichen in der funktionalen tests.

In Anbetracht der Tatsache das der verlinkte thread ist von 2013. Gibt es andere Optionen?

BEARBEITEN

Also ich habe gelesen, die gorilla/mux source-code, und nach mux.go die Funktion mux.Vars() definiert ist hier wie diese :

//Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
    if rv := context.Get(r, varsKey); rv != nil {
        return rv.(map[string]string)
    }
    return nil
}

Den Wert varsKey ist definiert als iota hier. So im wesentlichen, wird der Wert des Schlüssels 0. Ich habe eine schriftliche kleine test-app zu prüfen :
main.gehen

package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/gorilla/context"
)

func main() {
    r, _ := http.NewRequest("GET", "/test/abcd", nil)
    vars := map[string]string{
        "mystring": "abcd",
    }
    context.Set(r, 0, vars)
    what := Vars(r)

    for key, value := range what {
        fmt.Println("Key:", key, "Value:", value)
    }

    what2 := mux.Vars(r)
    fmt.Println(what2)

    for key, value := range what2 {
        fmt.Println("Key:", key, "Value:", value)
    }

}

func Vars(r *http.Request) map[string]string {
    if rv := context.Get(r, 0); rv != nil {
        return rv.(map[string]string)
    }
    return nil
}

Welche, wenn Sie ausgeführt werden, Ausgänge :

Key: mystring Value: abcd
map[]

Was mich Wundern lässt, warum der test nicht funktioniert und warum der direkte Aufruf zu mux.Vars funktioniert nicht.

Schreibe einen Kommentar