unit testing golang handler

huangapple go评论75阅读模式
英文:

unit testing golang handler

问题

以下是翻译好的内容:

这是我编写的一个处理程序,用于从mongodb中检索文档。
如果找到文档,我们将相应地加载和渲染模板。
如果失败,将重定向到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)

}

手动尝试时,一切都正常工作。

然而,我似乎无法通过单元测试。在相应的测试文件中,这是我尝试加载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)
    }

}

测试在EventNextHandler(response, request)这一行失败。

在我的错误消息中,它引用了处理程序代码中的err := db.Find(&Event{}, search).Sort(sort).One(&result)这一行。

完整的错误消息如下:

=== 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

请问编写测试的正确方法是什么?如何考虑从mongodb中未检索到任何内容的情况,并应用断言来验证,从而编写一个经过验证的测试。

英文:

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.

答案1

得分: 7

看起来我在测试中没有初始化db。就像其他语言的单元测试框架一样,我必须确保导入了我的db包,并实现两行代码来连接数据库和注册索引。

func TestEventNextHandler(t *testing.T) {

    // 设置测试数据库

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

    // 对EventNextHandler的HTTP请求进行集成测试

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

    EventNextHandler(response, request)

    if response.Code != 302 {
        t.Fatalf("非预期的状态码 %v:\n\tbody: %v", "200", response.Code)
    }

}

以上是要翻译的内容。

英文:

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)
	}

}

huangapple
  • 本文由 发表于 2013年11月4日 15:04:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/19763077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定