Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unit testing golang handler

Here's a handler I wrote to retrieve a document from mongodb.
If the document is found, we will load and render the template accordingly. If it fails, it will redirect to 404.

func EventNextHandler(w http.ResponseWriter, r *http.Request) {

    search := bson.M{"data.start_time": bson.M{"$gte": time.Now()}}
    sort := "data.start_time"
    var result *Event
    err := db.Find(&Event{}, search).Sort(sort).One(&result)
    if err != nil && err != mgo.ErrNotFound {
        panic(err)
    }
    if err == mgo.ErrNotFound {
        fmt.Println("No such object in db. Redirect")
        http.Redirect(w, r, "/404/", http.StatusFound)
        return
    }

    // TODO: 
    // This is the absolute path parsing of template files so tests will pass
    // Code can be better organized
    var eventnext = template.Must(template.ParseFiles(
        path.Join(conf.Config.ProjectRoot, "templates/_base.html"),
        path.Join(conf.Config.ProjectRoot, "templates/event_next.html"),
    ))

    type templateData struct {
        Context *conf.Context
        E *Event
    }

    data := templateData{conf.DefaultContext(conf.Config), result}

    eventnext.Execute(w, data)

}

Manually trying this out, everything works great.

However, I can't seem to get this to pass my unit tests. In a corresponding test file, this is my test code to attempt to load my EventNextHandler.

func TestEventNextHandler(t *testing.T) {

    // integration test on http requests to EventNextHandler

    request, _ := http.NewRequest("GET", "/events/next/", nil)
    response := httptest.NewRecorder()

    EventNextHandler(response, request)

    if response.Code != http.StatusOK {
        t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
    }

}

The test fails at the line stating EventNextHandler(response, request).

And in my error message, it refers to the line err := db.Find(&Event{}, search).Sort(sort).One(&result) in my handler code.

Complete error message here:-

=== RUN TestEventNextHandler
--- FAIL: TestEventNextHandler (0.00 seconds)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x8 pc=0x113eb8]

goroutine 4 [running]:
testing.func·004()
    /usr/local/go/src/pkg/testing/testing.go:348 +0xcd
hp/db.Cursor(0xc2000c3cf0, 0xc2000fb1c0, 0x252d00)
    /Users/calvin/gopath/src/hp/db/db.go:57 +0x98
hp/db.Find(0xc2000c3cf0, 0xc2000fb1c0, 0x252d00, 0xc2000e55c0, 0x252d00, ...)
    /Users/calvin/gopath/src/hp/db/db.go:61 +0x2f
hp/event.EventNextHandler(0xc2000e5580, 0xc2000a16a0, 0xc2000c5680)
    /Users/calvin/gopath/src/hp/event/controllers.go:106 +0x1da
hp/event.TestEventNextHandler(0xc2000d5240)
    /Users/calvin/gopath/src/hp/event/controllers_test.go:16 +0x107
testing.tRunner(0xc2000d5240, 0x526fe0)
    /usr/local/go/src/pkg/testing/testing.go:353 +0x8a
created by testing.RunTests
    /usr/local/go/src/pkg/testing/testing.go:433 +0x86b

goroutine 1 [chan receive]:
testing.RunTests(0x3bdff0, 0x526fe0, 0x1, 0x1, 0x1, ...)
    /usr/local/go/src/pkg/testing/testing.go:434 +0x88e
testing.Main(0x3bdff0, 0x526fe0, 0x1, 0x1, 0x532580, ...)
    /usr/local/go/src/pkg/testing/testing.go:365 +0x8a
main.main()
    hp/event/_test/_testmain.go:43 +0x9a

What is the correct way to write my tests? To take into account the situation where nothing gets retrieved from mongodb and apply an assertion to verify that, thus writing a validated test.

like image 515
Calvin Cheng Avatar asked Nov 04 '13 07:11

Calvin Cheng


1 Answers

It appears that I did not initialize db in my test. Much like a "setup" step similar to all other languages' unit testing framework.

I have to ensure that my db package is imported and then implement two lines to Connect to the database and register the indexes.

func TestEventNextHandler(t *testing.T) {

    // set up test database

    db.Connect("127.0.0.1", "test_db")
    db.RegisterAllIndexes()

    // integration test on http requests to EventNextHandler

    request, _ := http.NewRequest("GET", "/events/next/", nil)
    response := httptest.NewRecorder()

    EventNextHandler(response, request)

    if response.Code != 302 {
        t.Fatalf("Non-expected status code %v:\n\tbody: %v", "200", response.Code)
    }

}
like image 140
Calvin Cheng Avatar answered Sep 27 '22 17:09

Calvin Cheng