如何测试实现大猩猩上下文的功能

I wrote a functions that save data into redis database server. The challenge is that I want to test these functions and do not know how to test it.

I just start somehow with

Functions

package sessrage

/*
 * Save data into redis database. In the common case,
 * the data will be only valid during a request. Use
 * hash datatype in redis.
 */

import (
    "../context"
    "github.com/garyburd/redigo/redis"
    "net/http"
)

const (
    protocol string = "tcp"
    port     string = ":6379"
)

func connectAndCloseRedis(connectCall func(con redis.Conn)) {

    c, err := redis.Dial("tcp", ":6379")
    defer c.Close()
    if err != nil {
        panic(err.Error())
    }
    connectCall(c)
}

func PostSessionData(r *http.Request, key, value string) {

    go connectAndCloseRedis(func(con redis.Conn) {
        sessionId := context.Get(r, context.JwtId).(string)
        con.Do("HMSET", sessionId, key, value)
    })
}

func GetSessionData(r *http.Request, key string) interface{} {

    var result interface{}

    sessionId := context.Get(r, context.JwtId).(string)
    reply, _ := redis.Values(c.Do("HMGET", sessionId, key))
    redis.Scan(reply, &result)
    return result
}

and the test file

package sessrage

import (
    //"fmt"
    "../context"
    . "github.com/smartystreets/goconvey/convey"
    "github.com/stretchr/testify/assert"
    "net/http"
    "net/http/httptest"
    "testing"
    "time"
)

var server *httptest.Server
var glrw http.ResponseWriter
var glr *http.Request

func init() {
    server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
        glrw = rw
        glr = r

        context.Set(glr, context.JwtId, "TestId")
    }))

}

func TestPostAndGetSession(t *testing.T) {

    Convey("POST and GET data on redis.", t, func() {

        PostSessionData(glr, "key1", "value1")

        time.Sleep(time.Second * 10)
        v := GetSessionData(glr, "key1")

        assert.Equal(t, "value1", v)
    })
}

when I try to run the test I've got

an't load package: ......./sessrage.go:10:2: local import "../context" in non-local package

and the context package looks like

package context

import (
    "github.com/gorilla/context"
    "net/http"
)

type contextKey int

const (
    LanguageId contextKey = iota
    JwtId
)

func Get(r *http.Request, key interface{}) interface{} {
    return context.Get(r, key)
}

func Set(r *http.Request, key, val interface{}) {
    context.Set(r, key, val)
}

What do I wrong?

That is the first time, I am testing code in conjunction with http. It seems to be very hard to test.

There are a few issues:

  • Don't use relative import paths.
  • Use a pool instead of dialing redis on every action.
  • The call to sessionId := context.Get(r, context.JwtId).(string) in the PostSessionData anonymous function can fail if the mux or something higher in the call chain clears the Gorilla context before the goroutine runs. Do this instead:

    func PostSessionData(r *http.Request, key, value string) {
        c := pool.Get()
        defer c.Close()
        sessionId := context.Get(r, context.JwtId).(string)
        if err := c.Do("HMSET", sessionId, key, value); err != nil {
           // handle error
        }
    }