0.1、索引
https://blog.waterflow.link/articles/1663688140724
1、简介
单元测试是测试代码、组件和模块的单元函数。单元测试的目标是革除代码中的谬误,减少代码的稳定性,在更改代码时提供正确性。单元测试是软件测试的第一级,而后是集成测试和 ui 测试。
2、编写测试代码
首先测试文件的命名必须以 _test.go
结尾,测试方法必须以 Test
结尾
咱们创立一个 testexample 我的项目,执行 go mod init
初始化我的项目。
而后创立一个 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
// 如果链接中有空字符串,返回默认值和谬误
if strings.Contains(uri, " ") {return builder, errURIWhitespace}
// 解析 url 为构造体,解析失败返回默认值和谬误
u, err := url.Parse(uri)
if err != nil {return builder, err}
// 依据 scheme 获取默认端口
defaultPort, okScheme := schemePorts[u.Scheme]
if okScheme {builder.Scheme = u.Scheme} else {
// 获取不到就返回默认值和谬误
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 {
// 解析进去的端口转整型失败,返回最新的 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,"///") {
// 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()}
先不必思考下面函数的复杂性,咱们的目标很简略,就是要测试 ParseURI
函数。那如何测试呢?首先咱们须要创立一个 uri_test.go
文件,个别和须要测试的 uri.go
在同一个目录下。其次文件的包名也须要和uri.go
统一。
而后咱们就能够编写测试函数了,下面说了测试函数须要以 Test
结尾。
咱们先写一个简略的测试函数:
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:[email protected]:10000/vhost",
username: "user",
password: "pass",
host: "host",
port: 10000,
vhost: "vhost",
canon: "amqp://user:[email protected]:10000/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
结尾的测试函数TestUri
。函数的入参就代表这是一个单元测试。
而后咱们定义一个须要测试的 url 的构造 testURI
,而后初始化构造体uriTest
。其中uriTest.url
就是须要传入 ParseURI
的参数,另外的一些参数就是解析之后心愿返回的后果。
能够看到下面有几个办法:
- t.Fatal,测试谬误并退出
- t.Error,测试谬误会持续往下执行
- t.Log,个别代表测试胜利打印日志
3、运行测试代码
而后咱们在命令行执行下这个测试函数:
go test -run TestUri
PASS
ok go-demo/testexample/uri 0.390s
从执行后果咱们能够看到测试胜利了,然而并没有打印胜利的日志。这是因为咱们须要加上一个参数,批改如下:
go test -v -run TestUri
=== RUN TestUri
uri_test.go:37: For: amqp://user:[email protected]:10000/vhost usernames match. want: user got: user
--- PASS: TestUri (0.00s)
PASS
ok go-demo/testexample/uri 0.120s
能够看到测试胜利的日志打印进去了。
-run
代表能够指定某个具体的测试函数执行,如果去掉的话也能够,会执行这个目录下所有的测试函数
4、表驱动测试
如果咱们想执行一批测试代码,这个时候应该怎么写呢?很简略,咱们只须要定义一个切片就行:
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:[email protected]:10000/vhost",
username: "user",
password: "pass",
host: "host",
port: 10000,
vhost: "vhost",
canon: "amqp://user:[email protected]:10000/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://[email protected]",
username: "user",
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[email protected]/",
},
{url: "amqp://user:[email protected]",
username: "user",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user:[email protected]/",
},
{url: "amqp://guest:[email protected]",
username: "guest",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://guest:[email protected]/",
},
{
url: "amqp://host",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://:10000",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: 10000,
vhost: defaultURI.Vhost,
canon: "amqp://localhost:10000/",
},
{
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: "//",
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
是咱们定义的一个切片,只须要在测试函数中遍历以下即可。
5、测试覆盖率
测试覆盖率是应用程序中代码覆盖率的测量百分比。理解测试笼罩了多少代码很重要。通过这种形式,您能够看到代码的哪些局部您曾经测试过,哪些局部咱们没有测试过。
Go 的规范库提供了内置的测试笼罩来查看你的代码覆盖率。
咱们批改下测试代码如下:
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:[email protected]:10000/vhost",
username: "user",
password: "pass",
host: "host",
port: 10000,
vhost: "vhost",
canon: "amqp://user:[email protected]:10000/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://[email protected]",
username: "user",
password: defaultURI.Password,
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://[email protected]/",
},
{url: "amqp://user:[email protected]",
username: "user",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://user:[email protected]/",
},
{url: "amqp://guest:[email protected]",
username: "guest",
password: "pass",
host: defaultURI.Host,
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://guest:[email protected]/",
},
{
url: "amqp://host",
username: defaultURI.Username,
password: defaultURI.Password,
host: "host",
port: defaultURI.Port,
vhost: defaultURI.Vhost,
canon: "amqp://host/",
},
{
url: "amqp://:10000",
username: defaultURI.Username,
password: defaultURI.Password,
host: defaultURI.Host,
port: 10000,
vhost: defaultURI.Vhost,
canon: "amqp://localhost:10000/",
},
{
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: "//",
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:[email protected]/ -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:[email protected]: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)
}
}
而后执行:
go test -cover
PASS
coverage: 88.0% of statements
ok go-demo/testexample/uri 0.385s
能够看到测试通过,覆盖率是 88%。阐明咱们还有一些代码分支没有测试到,那咱们如何去看这些没有笼罩到的代码分支呢?
很简略,还是 go test
命令:
go test -coverprofile=cover_out
PASS
coverage: 88.0% of statements
ok go-demo/testexample/uri 0.119s
执行实现后咱们能够看到目录中多了 cover_out
文件
tree
.
├── cover_out
├── uri.go
└── uri_test.go
咱们看下这个文件里能找到没有笼罩到的代码么?
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
看的我是一脸懵逼,不过别着急咱们能够把这个文件转成咱们想要的 html 格局:
go tool cover -html=cover_out -o cover_out.html
看下目录中是不是多了个 html
tree
.
├── cover_out
├── cover_out.html
├── uri.go
└── uri_test.go
咱们浏览器关上这个文件,会看到上面这个界面,不要太爽:
红色的就是代表咱们测试没有笼罩到的。只须要丰盛下测试代码,就能够做到 100% 笼罩了。这部分就由你本人实现吧。
6、基准测试
通过 Benchmarking,您能够掂量代码的性能并查看您对代码所做的更改的影响,从而优化您的源代码。
文件名必须以 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:[email protected]:10000/vhost",
username: "user",
password: "pass",
host: "host",
port: 10000,
vhost: "vhost",
canon: "amqp://user:[email protected]:10000/vhost",
}
func BenchmarkUri(b *testing.B) {
for i := 0; i < b.N; i++ {_, _ = ParseURI(uriTest.url)
}
}
- 基准函数必须带参数 测试。B
- Benchmark 必须运行 N 次 testing.B 提供(N 是整数类型,从 Go 调整)
- 当提供 -bench 标记时,由“go test”命令执行。
- 该
-bench
标记以正则表达式的模式承受其参数。
执行命令如下:
go test -bench=.
goos: darwin
goarch: amd64
pkg: go-demo/testexample/uri
cpu: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
BenchmarkUri-8 2041880 579.2 ns/op
PASS
ok go-demo/testexample/uri 2.075s
基准测试后果意味着基准测试通过。循环运行 2041880 次,每个循环速度为 579.2 纳秒。