https://blog.waterflow.link/articles/
10多年的阜康網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整阜康建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)從事“阜康網(wǎng)站設(shè)計”,“阜康網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。
單元測試是測試代碼、組件和模塊的單元函數(shù)。單元測試的目的是清除代碼中的錯誤,增加代碼的穩(wěn)定性,在更改代碼時提供正確性。單元測試是軟件測試的第一級,然后是集成測試和 ui 測試。
首先測試文件的命名必須以_test.go
結(jié)尾,測試方法必須以Test
開頭
我們創(chuàng)建一個testexample項目,執(zhí)行go mod init
初始化項目。
然后創(chuàng)建一個uri.go的文件,里面的代碼是我摘抄自golang的amqp包中的一段解析ampq url的代碼,具體鏈接
package uri
import (
"errors"
"net"
"net/url"
"strconv"
"strings"
)
var errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'")
var errURIWhitespace = errors.New("URI must not contain whitespace")
var schemePorts = map[string]int{
"amqp": 5672,
"amqps": 5671,
}
var defaultURI = URI{
Scheme: "amqp",
Host: "localhost",
Port: 5672,
Username: "guest",
Password: "guest",
Vhost: "/",
}
// URI represents a parsed AMQP URI string.
type URI struct {
Scheme string
Host string
Port int
Username string
Password string
Vhost string
}
// ParseURI attempts to parse the given AMQP URI according to the spec.
// See http://www.rabbitmq.com/uri-spec.html.
//
// Default values for the fields are:
//
// Scheme: amqp
// Host: localhost
// Port: 5672
// Username: guest
// Password: guest
// Vhost: /
//
func ParseURI(uri string) (URI, error) {
builder := defaultURI
// 如果鏈接中有空字符串,返回默認(rèn)值和錯誤
if strings.Contains(uri, " ") {
return builder, errURIWhitespace
}
// 解析url為結(jié)構(gòu)體,解析失敗返回默認(rèn)值和錯誤
u, err := url.Parse(uri)
if err != nil {
return builder, err
}
// 根據(jù)scheme獲取默認(rèn)端口
defaultPort, okScheme := schemePorts[u.Scheme]
if okScheme {
builder.Scheme = u.Scheme
} else {
// 獲取不到就返回默認(rèn)值和錯誤
return builder, errURIScheme
}
host := u.Hostname()
port := u.Port()
if host != "" {
builder.Host = host
}
if port != "" {
port32, err := strconv.ParseInt(port, 10, 32)
if err != nil {
// 解析出來的端口轉(zhuǎn)整型失敗,返回最新的URI和錯誤
return builder, err
}
builder.Port = int(port32)
} else {
builder.Port = defaultPort
}
if u.User != nil {
builder.Username = u.User.Username()
if password, ok := u.User.Password(); ok {
builder.Password = password
}
}
if u.Path != "" {
if strings.HasPrefix(u.Path, "/") {
if u.Host == "" && strings.HasPrefix(u.Path, "http:///") {
// net/url doesn't handle local context authorities and leaves that up
// to the scheme handler. In our case, we translate amqp:/// into the
// default host and whatever the vhost should be
if len(u.Path) > 3 {
builder.Vhost = u.Path[3:]
}
} else if len(u.Path) > 1 {
builder.Vhost = u.Path[1:]
}
} else {
builder.Vhost = u.Path
}
}
return builder, nil
}
func (uri URI) String() string {
authority, err := url.Parse("")
if err != nil {
return err.Error()
}
authority.Scheme = uri.Scheme
if uri.Username != defaultURI.Username || uri.Password != defaultURI.Password {
authority.User = url.User(uri.Username)
if uri.Password != defaultURI.Password {
authority.User = url.UserPassword(uri.Username, uri.Password)
}
}
authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port))
if defaultPort, found := schemePorts[uri.Scheme]; !found || defaultPort != uri.Port {
authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port))
} else {
// JoinHostPort() automatically add brackets to the host if it's
// an IPv6 address.
//
// If not port is specified, JoinHostPort() return an IP address in the
// form of "[::1]:", so we use TrimSuffix() to remove the extra ":".
authority.Host = strings.TrimSuffix(net.JoinHostPort(uri.Host, ""), ":")
}
if uri.Vhost != defaultURI.Vhost {
// Make sure net/url does not double escape, e.g.
// "%2F" does not become "%252F".
authority.Path = uri.Vhost
authority.RawPath = url.QueryEscape(uri.Vhost)
} else {
authority.Path = "/"
}
return authority.String()
}
先不用考慮上面函數(shù)的復(fù)雜性,我們的目的很簡單,就是要測試ParseURI
函數(shù)。那如何測試呢?首先我們需要創(chuàng)建一個uri_test.go
文件,一般和需要測試的uri.go
在同一個目錄下。其次文件的包名也需要和uri.go
一致。
然后我們就可以編寫測試函數(shù)了,上面說了測試函數(shù)需要以Test
開頭。
我們先寫一個簡單的測試函數(shù):
package uri
import (
"testing"
)
// Test matrix defined on http://www.rabbitmq.com/uri-spec.html
type testURI struct {
url string
username string
password string
host string
port int
vhost string
canon string
}
var uriTest = testURI{
url: "amqp://user:pass@host:/vhost",
username: "user",
password: "pass",
host: "host",
port: ,
vhost: "vhost",
canon: "amqp://user:pass@host:/vhost",
}
func TestUri(t *testing.T) {
u, err := ParseURI(uriTest.url)
if err != nil {
t.Fatal("Could not parse spec URI: ", uriTest.url, " err: ", err)
}
if uriTest.username != u.Username {
t.Error("For: ", uriTest.url, " usernames do not match. want: ", uriTest.username, " got: ", u.Username)
} else {
t.Log("For: ", uriTest.url, " usernames match. want: ", uriTest.username, " got: ", u.Username)
}
}
首先我們看到包名是uri
,然后我們定義了一個以Test
開頭的測試函數(shù)TestUri
。函數(shù)的入?yún)⒕痛磉@是一個單元測試。
然后我們定義一個需要測試的url的結(jié)構(gòu)testURI
,然后初始化結(jié)構(gòu)體uriTest
。其中uriTest.url
就是需要傳入ParseURI
的參數(shù),另外的一些參數(shù)就是解析之后希望返回的結(jié)果。
可以看到上面有幾個方法:
然后我們在命令行執(zhí)行下這個測試函數(shù):
go test -run TestUri
PASS
ok go-demo/testexample/uri 0.390s
從執(zhí)行結(jié)果我們可以看到測試成功了,但是并沒有打印成功的日志。這是因為我們需要加上一個參數(shù),修改如下:
go test -v -run TestUri
=== RUN TestUri
uri_test.go:37: For: amqp://user:pass@host:/vhost usernames match. want: user got: user
--- PASS: TestUri (0.00s)
PASS
ok go-demo/testexample/uri 0.120s
可以看到測試成功的日志打印出來了。
-run
代表可以指定某個具體的測試函數(shù)執(zhí)行,如果去掉的話也可以,會執(zhí)行這個目錄下所有的測試函數(shù)
如果我們想執(zhí)行一批測試代碼,這個時候應(yīng)該怎么寫呢?很簡單,我們只需要定義一個切片就行:
package uri
import (
"testing"
)
// Test matrix defined on http://www.rabbitmq.com/uri-spec.html
type testURI struct {
url string
username string
password string
host string
port int
vhost string
canon string
}
var uriTests = []testURI{
{
url: "amqp://user:pass@host:/vhost",
username: "user",
password: "pass",
host: "host",
port: ,
vhost: "vhost",
canon: "amqp://user:pass@host:/vhost",
},
{
url: "amqp://",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://localhost/",
},
{
url: "amqp://:@/",
username: "",
password: "",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://:@localhost/",
},
{
url: "amqp://user@",
username: "user",
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user@localhost/",
},
{
url: "amqp://user:pass@",
username: "user",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user:pass@localhost/",
},
{
url: "amqp://guest:pass@",
username: "guest",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://guest:pass@localhost/",
},
{
url: "amqp://host",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://:",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: ,
vhost: defaultURI.Vhost,
canon: "amqp://localhost:/",
},
{
url: "amqp:///vhost",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: "vhost",
canon: "amqp://localhost/vhost",
},
{
url: "amqp://host/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://host/%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "/",
canon: "amqp://host/",
},
{
url: "amqp://host/%2F%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "http://",
canon: "amqp://host/%2F%2F",
},
{
url: "amqp://host/%2Fslash%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "/slash/",
canon: "amqp://host/%2Fslash%2F",
},
{
url: "amqp://192.168.1.1:1000/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "192.168.1.1",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqp://192.168.1.1:1000/",
},
{
url: "amqp://[::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[::1]/",
},
{
url: "amqp://[::1]:1000",
username: defaultURI.Username,
password: defaultURI.Password,
host: "::1",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqp://[::1]:1000/",
},
{
url: "amqp://[fe80::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]/",
},
{
url: "amqp://[fe80::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]/",
},
{
url: "amqp://[fe80::1%25en0]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1%en0",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1%25en0]/",
},
{
url: "amqp://[fe80::1]:5671",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: 5671,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]:5671/",
},
{
url: "amqps:///",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: schemePorts["amqps"],
vhost: defaultURI.Vhost,
canon: "amqps://localhost/",
},
{
url: "amqps://host:1000/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqps://host:1000/",
},
}
func TestURISpec(t *testing.T) {
for _, test := range uriTests {
u, err := ParseURI(test.url)
if err != nil {
t.Fatal("Could not parse spec URI: ", test.url, " err: ", err)
}
if test.username != u.Username {
t.Error("For: ", test.url, " usernames do not match. want: ", test.username, " got: ", u.Username)
}
if test.password != u.Password {
t.Error("For: ", test.url, " passwords do not match. want: ", test.password, " got: ", u.Password)
}
if test.host != u.Host {
t.Error("For: ", test.url, " hosts do not match. want: ", test.host, " got: ", u.Host)
}
if test.port != u.Port {
t.Error("For: ", test.url, " ports do not match. want: ", test.port, " got: ", u.Port)
}
if test.vhost != u.Vhost {
t.Error("For: ", test.url, " vhosts do not match. want: ", test.vhost, " got: ", u.Vhost)
}
if test.canon != u.String() {
t.Error("For: ", test.url, " canonical string does not match. want: ", test.canon, " got: ", u.String())
}
}
}
uriTests
是我們定義的一個切片,只需要在測試函數(shù)中遍歷以下即可。
5、測試覆蓋率
測試覆蓋率是應(yīng)用程序中代碼覆蓋率的測量百分比。了解測試覆蓋了多少代碼很重要。通過這種方式,您可以看到代碼的哪些部分您已經(jīng)測試過,哪些部分我們沒有測試過。
Go 的標(biāo)準(zhǔn)庫提供了內(nèi)置的測試覆蓋來檢查你的代碼覆蓋率。
我們修改下測試代碼如下:
package uri
import (
"testing"
)
// Test matrix defined on http://www.rabbitmq.com/uri-spec.html
type testURI struct {
url string
username string
password string
host string
port int
vhost string
canon string
}
var uriTests = []testURI{
{
url: "amqp://user:pass@host:/vhost",
username: "user",
password: "pass",
host: "host",
port: ,
vhost: "vhost",
canon: "amqp://user:pass@host:/vhost",
},
{
url: "amqp://",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://localhost/",
},
{
url: "amqp://:@/",
username: "",
password: "",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://:@localhost/",
},
{
url: "amqp://user@",
username: "user",
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user@localhost/",
},
{
url: "amqp://user:pass@",
username: "user",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user:pass@localhost/",
},
{
url: "amqp://guest:pass@",
username: "guest",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://guest:pass@localhost/",
},
{
url: "amqp://host",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://:",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: ,
vhost: defaultURI.Vhost,
canon: "amqp://localhost:/",
},
{
url: "amqp:///vhost",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: "vhost",
canon: "amqp://localhost/vhost",
},
{
url: "amqp://host/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://host/%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "/",
canon: "amqp://host/",
},
{
url: "amqp://host/%2F%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "http://",
canon: "amqp://host/%2F%2F",
},
{
url: "amqp://host/%2Fslash%2F",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: "/slash/",
canon: "amqp://host/%2Fslash%2F",
},
{
url: "amqp://192.168.1.1:1000/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "192.168.1.1",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqp://192.168.1.1:1000/",
},
{
url: "amqp://[::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[::1]/",
},
{
url: "amqp://[::1]:1000",
username: defaultURI.Username,
password: defaultURI.Password,
host: "::1",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqp://[::1]:1000/",
},
{
url: "amqp://[fe80::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]/",
},
{
url: "amqp://[fe80::1]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]/",
},
{
url: "amqp://[fe80::1%25en0]",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1%en0",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1%25en0]/",
},
{
url: "amqp://[fe80::1]:5671",
username: defaultURI.Username,
password: defaultURI.Password,
host: "fe80::1",
port: 5671,
vhost: defaultURI.Vhost,
canon: "amqp://[fe80::1]:5671/",
},
{
url: "amqps:///",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: schemePorts["amqps"],
vhost: defaultURI.Vhost,
canon: "amqps://localhost/",
},
{
url: "amqps://host:1000/",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: 1000,
vhost: defaultURI.Vhost,
canon: "amqps://host:1000/",
},
}
func TestURISpec(t *testing.T) {
for _, test := range uriTests {
u, err := ParseURI(test.url)
if err != nil {
t.Fatal("Could not parse spec URI: ", test.url, " err: ", err)
}
if test.username != u.Username {
t.Error("For: ", test.url, " usernames do not match. want: ", test.username, " got: ", u.Username)
}
if test.password != u.Password {
t.Error("For: ", test.url, " passwords do not match. want: ", test.password, " got: ", u.Password)
}
if test.host != u.Host {
t.Error("For: ", test.url, " hosts do not match. want: ", test.host, " got: ", u.Host)
}
if test.port != u.Port {
t.Error("For: ", test.url, " ports do not match. want: ", test.port, " got: ", u.Port)
}
if test.vhost != u.Vhost {
t.Error("For: ", test.url, " vhosts do not match. want: ", test.vhost, " got: ", u.Vhost)
}
if test.canon != u.String() {
t.Error("For: ", test.url, " canonical string does not match. want: ", test.canon, " got: ", u.String())
}
}
}
func TestURIUnknownScheme(t *testing.T) {
if _, err := ParseURI("http://example.com/"); err == nil {
t.Fatal("Expected error when parsing non-amqp scheme")
}
}
func TestURIScheme(t *testing.T) {
if _, err := ParseURI("amqp://example.com/"); err != nil {
t.Fatalf("Expected to parse amqp scheme, got %v", err)
}
if _, err := ParseURI("amqps://example.com/"); err != nil {
t.Fatalf("Expected to parse amqps scheme, got %v", err)
}
}
func TestURIWhitespace(t *testing.T) {
if _, err := ParseURI("amqp://admin:PASSWORD@rabbitmq-service/ -http_port=8080"); err == nil {
t.Fatal("Expected to fail if URI contains whitespace")
}
}
func TestURIDefaults(t *testing.T) {
url := "amqp://"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.String() != "amqp://localhost/" {
t.Fatal("Defaults not encoded properly got:", uri.String())
}
}
func TestURIComplete(t *testing.T) {
url := "amqp://bob:dobbs@foo.bar:5678/private"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.String() != url {
t.Fatal("Defaults not encoded properly want:", url, " got:", uri.String())
}
}
func TestURIDefaultPortAmqpNotIncluded(t *testing.T) {
url := "amqp://foo.bar:5672/"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.String() != "amqp://foo.bar/" {
t.Fatal("Defaults not encoded properly got:", uri.String())
}
}
func TestURIDefaultPortAmqp(t *testing.T) {
url := "amqp://foo.bar/"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.Port != 5672 {
t.Fatal("Default port not correct for amqp, got:", uri.Port)
}
}
func TestURIDefaultPortAmqpsNotIncludedInString(t *testing.T) {
url := "amqps://foo.bar:5671/"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.String() != "amqps://foo.bar/" {
t.Fatal("Defaults not encoded properly got:", uri.String())
} else {
t.Logf("ParseURI(%s) execute success\n", url)
}
}
func TestURIDefaultPortAmqps(t *testing.T) {
url := "amqps://foo.bar/"
uri, err := ParseURI(url)
if err != nil {
t.Fatal("Could not parse")
}
if uri.Port != 5671 {
t.Fatal("Default port not correct for amqps, got:", uri.Port)
}
}
然后執(zhí)行:
go test -cover
PASS
coverage: 88.0% of statements
ok go-demo/testexample/uri 0.385s
可以看到測試通過,覆蓋率是88%。說明我們還有一些代碼分支沒有測試到,那我們?nèi)绾稳タ催@些沒有覆蓋到的代碼分支呢?
很簡單,還是go test
命令:
go test -coverprofile=cover_out
PASS
coverage: 88.0% of statements
ok go-demo/testexample/uri 0.119s
執(zhí)行完成后我們可以看到目錄中多了cover_out
文件
tree
.
├── cover_out
├── uri.go
└── uri_test.go
我們看下這個文件里能找到?jīng)]有覆蓋到的代碼么?
mode: set
go-demo/testexample/uri/uri.go:50.40,54.32 2 1
go-demo/testexample/uri/uri.go:59.2,60.16 2 1
go-demo/testexample/uri/uri.go:65.2,67.14 2 1
go-demo/testexample/uri/uri.go:74.2,77.16 3 1
go-demo/testexample/uri/uri.go:81.2,81.16 1 1
go-demo/testexample/uri/uri.go:92.2,92.19 1 1
go-demo/testexample/uri/uri.go:99.2,99.18 1 1
go-demo/testexample/uri/uri.go:116.2,116.21 1 1
go-demo/testexample/uri/uri.go:54.32,56.3 1 1
go-demo/testexample/uri/uri.go:60.16,62.3 1 0
go-demo/testexample/uri/uri.go:67.14,69.3 1 1
go-demo/testexample/uri/uri.go:69.8,72.3 1 1
go-demo/testexample/uri/uri.go:77.16,79.3 1 1
go-demo/testexample/uri/uri.go:81.16,83.17 2 1
go-demo/testexample/uri/uri.go:87.3,87.29 1 1
go-demo/testexample/uri/uri.go:83.17,86.4 1 0
go-demo/testexample/uri/uri.go:88.8,90.3 1 1
go-demo/testexample/uri/uri.go:92.19,94.44 2 1
go-demo/testexample/uri/uri.go:94.44,96.4 1 1
go-demo/testexample/uri/uri.go:99.18,100.37 1 1
go-demo/testexample/uri/uri.go:100.37,101.56 1 1
go-demo/testexample/uri/uri.go:101.56,105.24 1 0
go-demo/testexample/uri/uri.go:105.24,107.6 1 0
go-demo/testexample/uri/uri.go:108.10,108.30 1 1
go-demo/testexample/uri/uri.go:108.30,110.5 1 1
go-demo/testexample/uri/uri.go:111.9,113.4 1 0
go-demo/testexample/uri/uri.go:119.32,121.16 2 1
go-demo/testexample/uri/uri.go:125.2,127.80 2 1
go-demo/testexample/uri/uri.go:135.2,137.86 2 1
go-demo/testexample/uri/uri.go:148.2,148.35 1 1
go-demo/testexample/uri/uri.go:157.2,157.27 1 1
go-demo/testexample/uri/uri.go:121.16,123.3 1 0
go-demo/testexample/uri/uri.go:127.80,130.42 2 1
go-demo/testexample/uri/uri.go:130.42,132.4 1 1
go-demo/testexample/uri/uri.go:137.86,139.3 1 1
go-demo/testexample/uri/uri.go:139.8,146.3 1 1
go-demo/testexample/uri/uri.go:148.35,153.3 2 1
go-demo/testexample/uri/uri.go:153.8,155.3 1 1
看的我是一臉懵逼,不過別著急我們可以把這個文件轉(zhuǎn)成我們想要的html格式:
go tool cover -html=cover_out -o cover_out.html
看下目錄中是不是多了個html
tree
.
├── cover_out
├── cover_out.html
├── uri.go
└── uri_test.go
我們?yōu)g覽器打開這個文件,會看到下面這個界面,不要太爽:
紅色的就是代表我們測試沒有覆蓋到的。只需要豐富下測試代碼,就可以做到100%覆蓋了。這部分就由你自己完成吧。
6、基準(zhǔn)測試
通過 Benchmarking,您可以衡量代碼的性能并查看您對代碼所做的更改的影響,從而優(yōu)化您的源代碼。
文件名必須以 Benchmark 前綴作為單元測試文件名約定。(BenchmarkSomething(*testing.B))
package uri
import (
"testing"
)
// Test matrix defined on http://www.rabbitmq.com/uri-spec.html
type testURI struct {
url string
username string
password string
host string
port int
vhost string
canon string
}
var uriTest = testURI{
url: "amqp://user:pass@host:/vhost",
username: "user",
password: "pass",
host: "host",
port: ,
vhost: "vhost",
canon: "amqp://user:pass@host:/vhost",
}
func BenchmarkUri(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = ParseURI(uriTest.url)
}
}
-bench
標(biāo)志以正則表達(dá)式的形式接受其參數(shù)。執(zhí)行命令如下:
go test -bench=.
goos: darwin
goarch: amd64
pkg: go-demo/testexample/uri
cpu: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
BenchmarkUri-8 579.2 ns/op
PASS
ok go-demo/testexample/uri 2.075s
基準(zhǔn)測試結(jié)果意味著基準(zhǔn)測試通過。循環(huán)運行 次,每個循環(huán)速度為 579.2 納秒。