单元测试
单元测试是用来测试包或者程序的一部分代码或者一组代码的函数。
基础测试
只使用一组参数和结果来测试一段代码
go01_test.go
文件
package go01
import (
"net/http"
"testing"
)
const checkMark = "\u2713"
const ballotX = "\u2717"
func TestDownload(t *testing.T) {
url := "http://www.baidu.com"
statusCode := 200
t.Log("Given the need to test downloading content.")
{
t.Logf("\tWhen checking \"%s\" for status code \"%d\"",
url, statusCode)
{
resp, err := http.Get(url)
if err != nil {
t.Fatal("\t\tShould be able to make the Get call.",
ballotX, err)
}
t.Log("\t\tShould be able to make the Get call.",
checkMark)
defer resp.Body.Close()
if resp.StatusCode == statusCode {
t.Logf("\t\tShould receive a \"%d\" status. %v",
statusCode, checkMark)
} else {
t.Errorf("\t\tShould receive a \"%d\" status. %v %v",
statusCode, ballotX, resp.StatusCode)
}
}
}
}
结果如下:
=== RUN TestDownload
--- PASS: TestDownload (1.15s)
listing01_test.go:15: Given the need to test downloading content.
listing01_test.go:17: When checking "http://www.baidu.com" for status code "200"
listing01_test.go:25: Should be able to make the Get call. ✓
listing01_test.go:31: Should receive a "200" status. ✓
PASS
表组测试
go02_test.go
文件
package go02
import (
"net/http"
"testing"
)
const checkMark = "\u2713"
const ballotX = "\u2717"
func TestDownload(t *testing.T) {
var urls = []struct {
url string
statusCode int
}{
{
"http://www.baidu.com",
http.StatusOK,
},
{
"http://www.goinggo.net/feeds/posts/default?alt=rss",
http.StatusNotFound,
},
}
t.Log("Given the need to test downloading different content.")
{
for _, u := range urls {
t.Logf("\tWhen checking \"%s\" for status code \"%d\"",
u.url, u.statusCode)
{
resp, err := http.Get(u.url)
if err != nil {
t.Fatal("\t\tShould be able to Get the url.",
ballotX, err)
}
t.Log("\t\tShould be able to Get the url.",
checkMark)
defer resp.Body.Close()
if resp.StatusCode == u.statusCode {
t.Logf("\t\tShould have a \"%d\" status. %v",
u.statusCode, checkMark)
} else {
t.Errorf("\t\tShould have a \"%d\" status. %v %v",
u.statusCode, ballotX, resp.StatusCode)
}
}
}
}
}
结果如下:
=== RUN TestDownload
--- PASS: TestDownload (5.15s)
listing08_test.go:28: Given the need to test downloading different content.
listing08_test.go:31: When checking "http://www.baidu.com" for status code "200"
listing08_test.go:39: Should be able to Get the url. ✓
listing08_test.go:45: Should have a "200" status. ✓
listing08_test.go:31: When checking "http://www.goinggo.net/feeds/posts/default?alt=rss" for status code "404"
listing08_test.go:39: Should be able to Get the url. ✓
listing08_test.go:45: Should have a "404" status. ✓
PASS
mock
go03_test.go
文件
package go03
import (
"encoding/xml"
"fmt"
"net/http"
"net/http/httptest"
"testing"
)
const checkMark = "\u2713"
const ballotX = "\u2717"
// feed is mocking the XML document we except to receive.
var feed = `<?xml version="1.0" encoding="UTF-8"?>
<rss>
<channel>
<title>Going Go Programming</title>
<description>Golang : https://github.com/goinggo</description>
<link>http://www.goinggo.net/</link>
<item>
<pubDate>Sun, 15 Mar 2015 15:04:00 +0000</pubDate>
<title>Object Oriented Programming Mechanics</title>
<description>Go is an object oriented language.</description>
<link>http://www.goinggo.net/2015/03/object-oriented</link>
</item>
</channel>
</rss>`
// mockServer returns a pointer to a server to handle the get call.
func mockServer() *httptest.Server {
f := func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/xml")
fmt.Fprintln(w, feed)
}
return httptest.NewServer(http.HandlerFunc(f))
}
func TestDownload(t *testing.T) {
statusCode := http.StatusOK
server := mockServer()
defer server.Close()
t.Log("Given the need to test downloading content.")
{
t.Logf("\tWhen checking \"%s\" for status code \"%d\"",
server.URL, statusCode)
{
resp, err := http.Get(server.URL)
if err != nil {
t.Fatal("\t\tShould be able to make the Get call.",
ballotX, err)
}
t.Log("\t\tShould be able to make the Get call.",
checkMark)
defer resp.Body.Close()
if resp.StatusCode != statusCode {
t.Fatalf("\t\tShould receive a \"%d\" status. %v %v",
statusCode, ballotX, resp.StatusCode)
}
t.Logf("\t\tShould receive a \"%d\" status. %v",
statusCode, checkMark)
var d Document
if err := xml.NewDecoder(resp.Body).Decode(&d); err != nil {
t.Fatal("\t\tShould be able to unmarshal the response.",
ballotX, err)
}
t.Log("\t\tShould be able to unmarshal the response.",
checkMark)
if len(d.Channel.Items) == 1 {
t.Log("\t\tShould have \"1\" item in the feed.",
checkMark)
} else {
t.Error("\t\tShould have \"1\" item in the feed.",
ballotX, len(d.Channel.Items))
}
}
}
}
type Item struct {
XMLName xml.Name `xml:"item"`
Title string `xml:"title"`
Description string `xml:"description"`
Link string `xml:"link"`
}
type Channel struct {
XMLName xml.Name `xml:"channel"`
Title string `xml:"title"`
Description string `xml:"description"`
Link string `xml:"link"`
PubDate string `xml:"pubDate"`
Items []Item `xml:"item"`
}
type Document struct {
XMLName xml.Name `xml:"rss"`
Channel Channel `xml:"channel"`
URI string
}
结果如下:
=== RUN TestDownload
--- PASS: TestDownload (0.00s)
listing12_test.go:49: Given the need to test downloading content.
listing12_test.go:51: When checking "http://127.0.0.1:52486" for status code "200"
listing12_test.go:59: Should be able to make the Get call. ✓
listing12_test.go:68: Should receive a "200" status. ✓
listing12_test.go:76: Should be able to unmarshal the response. ✓
listing12_test.go:80: Should have "1" item in the feed. ✓
PASS
基准测试
go04_test.go
文件
package go04
import (
"fmt"
"strconv"
"testing"
)
func BenchmarkSprintf(b *testing.B) {
number := 10
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Sprintf("%d", number)
}
}
func BenchmarkFormat(b *testing.B) {
number := int64(10)
b.ResetTimer()
for i := 0; i < b.N; i++ {
strconv.FormatInt(number, 10)
}
}
func BenchmarkItoa(b *testing.B) {
number := 10
b.ResetTimer()
for i := 0; i < b.N; i++ {
strconv.Itoa(number)
}
}
结果如下:
go test -v -bench=. -benchmem
goos: darwin
goarch: amd64
代码被执行的次数 每次操作消耗的纳秒 每次操作分配的字节数 每次操作从堆上分配内存的次数
BenchmarkSprintf-8 20000000 85.4 ns/op
BenchmarkFormat-8 500000000 3.16 ns/op
BenchmarkItoa-8 300000000 4.56 ns/op
PASS