前言
作为一名合格的开发者,不应该在程序开发完之后才开始写测试代码
1. 单元测试
使用Go标准库中的testing包来完成我们的单元测试
注意测试函数的写法:
func TestDownload(t *testing.T)
- 函数以大写
Test开头 - 函数参数中包含且只有一个参数
t *testing.T
package testinglearn
import (
"net/http"
"testing"
)
const checkMark = "\u2713" //对号(√)
const ballotX = "\u2717" //叉号(×)
// TestDownload 确认 http 包的 Get 函数可以下载内容
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)
}
}
}
}
通过调用 go test -v 来运行这个测试(-v 表示提供冗余输出),
Running tool: D:\go\bin\go.exe test -timeout 30s -run ^TestDownload$ gogo/test/testinglearn
=== RUN TestDownload
d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:16: Given the need to test downloading content.
d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:18: When checking http://www.baidu.com for status code 200
d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:24: Should be able to make the Get call. ✓
d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:29: Should receive a 200 status. ✓
--- PASS: TestDownload (0.09s)
PASS
ok gogo/test/testinglearn (cached)
Go 语言的测试工具只会认为以_test.go 结尾的文件是测试文件。如果没有遵从这个约定,在包里 运行 go test 的时候就可能会报告没有测试文件。一旦测试工具找到了测试文件,就会查找里 面的测试函数并执行
t.log
使用方法 t.Log来输出测试的消息,可写本次单元测试具体的内容
t.logf
可以格式化消息,与printf类似
t.Logf("\tWhen checking %s for status code %d", url, statusCode)
t.Fatal
t.Fatal 方法,让测试框架知道这个测试失败了。t.Fatal方法不但报告这个单元测试已经失败,而且会向测试输出写一些消息,而后立刻停止这个测试函数的执行。
t.Error
如果需要报告测试失败,但是并不想停止当前测试函数的执行,可以使用 t.Error 系列方法
2. 表组测试
如果测试可以接受一组不同的输入并产生不同的输出的代码,那么应该使用表组测试的方法 进行测试。表组测试除了会有一组不同的输入值和期望结果之外,其余部分都很像基础单元测试。
其实跟单元测试没有太大区别,我们只需将单元测试的代码稍作修改即可
package testinglearn
import (
"net/http"
"testing"
)
// TestDownload 确认 http 包的 Get 函数可以下载内容
// 并正确处理不同的状态
func TestDownload2(t *testing.T) {
var urls = []struct {
url string
statusCode int
}{
{
"http://www.baidu.com",
http.StatusOK,
},
{
"http://www.test03d1.com",
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 TestDownload2
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:25: Given the need to test downloading different content.
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:28: When checking "http://www.baidu.com" for status code "200"
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:36: Should be able to Get the url ✓
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:42: Should have a "200" status. ✓
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:28: When checking "http://www.test03d1.com" for status code "404"
d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:33: Should be able to Get the url. ✗ Get "http://www.test03d1.com": dial tcp: lookup www.test03d1.com: no such host
--- FAIL: TestDownload2 (0.08s)
FAIL
FAIL gogo/test/testinglearn 0.679s
> Test run finished at 4/4/2023, 4:57:51 PM <
我们定义了一个新的结构体数组 urls,里面存储我们需要进行测试的一组数据
var urls = []struct {
url string
statusCode int
}{
{
"http://www.baidu.com",
http.StatusOK,
},
{
"http://www.test03d1.com",
http.StatusNotFound,
},
}
再通过循环进行测试
for _, u := range urls {
...
}
参考书籍《Go语言实战》