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 uriimport (    "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 uriimport (    "testing")// Test matrix defined on http://www.rabbitmq.com/uri-spec.htmltype 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                         PASSok      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)PASSok      go-demo/testexample/uri 0.120s

能够看到测试胜利的日志打印进去了。

-run代表能够指定某个具体的测试函数执行,如果去掉的话也能够,会执行这个目录下所有的测试函数

4、表驱动测试

如果咱们想执行一批测试代码,这个时候应该怎么写呢?很简略,咱们只须要定义一个切片就行:

package uriimport (    "testing")// Test matrix defined on http://www.rabbitmq.com/uri-spec.htmltype 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 uriimport (    "testing")// Test matrix defined on http://www.rabbitmq.com/uri-spec.htmltype 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               PASScoverage: 88.0% of statementsok      go-demo/testexample/uri 0.385s

能够看到测试通过,覆盖率是88%。阐明咱们还有一些代码分支没有测试到,那咱们如何去看这些没有笼罩到的代码分支呢?

很简略,还是go test命令:

go test -coverprofile=cover_outPASScoverage: 88.0% of statementsok      go-demo/testexample/uri 0.119s

执行实现后咱们能够看到目录中多了cover_out文件

tree              .├── cover_out├── uri.go└── uri_test.go

咱们看下这个文件里能找到没有笼罩到的代码么?

mode: setgo-demo/testexample/uri/uri.go:50.40,54.32 2 1go-demo/testexample/uri/uri.go:59.2,60.16 2 1go-demo/testexample/uri/uri.go:65.2,67.14 2 1go-demo/testexample/uri/uri.go:74.2,77.16 3 1go-demo/testexample/uri/uri.go:81.2,81.16 1 1go-demo/testexample/uri/uri.go:92.2,92.19 1 1go-demo/testexample/uri/uri.go:99.2,99.18 1 1go-demo/testexample/uri/uri.go:116.2,116.21 1 1go-demo/testexample/uri/uri.go:54.32,56.3 1 1go-demo/testexample/uri/uri.go:60.16,62.3 1 0go-demo/testexample/uri/uri.go:67.14,69.3 1 1go-demo/testexample/uri/uri.go:69.8,72.3 1 1go-demo/testexample/uri/uri.go:77.16,79.3 1 1go-demo/testexample/uri/uri.go:81.16,83.17 2 1go-demo/testexample/uri/uri.go:87.3,87.29 1 1go-demo/testexample/uri/uri.go:83.17,86.4 1 0go-demo/testexample/uri/uri.go:88.8,90.3 1 1go-demo/testexample/uri/uri.go:92.19,94.44 2 1go-demo/testexample/uri/uri.go:94.44,96.4 1 1go-demo/testexample/uri/uri.go:99.18,100.37 1 1go-demo/testexample/uri/uri.go:100.37,101.56 1 1go-demo/testexample/uri/uri.go:101.56,105.24 1 0go-demo/testexample/uri/uri.go:105.24,107.6 1 0go-demo/testexample/uri/uri.go:108.10,108.30 1 1go-demo/testexample/uri/uri.go:108.30,110.5 1 1go-demo/testexample/uri/uri.go:111.9,113.4 1 0go-demo/testexample/uri/uri.go:119.32,121.16 2 1go-demo/testexample/uri/uri.go:125.2,127.80 2 1go-demo/testexample/uri/uri.go:135.2,137.86 2 1go-demo/testexample/uri/uri.go:148.2,148.35 1 1go-demo/testexample/uri/uri.go:157.2,157.27 1 1go-demo/testexample/uri/uri.go:121.16,123.3 1 0go-demo/testexample/uri/uri.go:127.80,130.42 2 1go-demo/testexample/uri/uri.go:130.42,132.4 1 1go-demo/testexample/uri/uri.go:137.86,139.3 1 1go-demo/testexample/uri/uri.go:139.8,146.3 1 1go-demo/testexample/uri/uri.go:148.35,153.3 2 1go-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 uriimport (    "testing")// Test matrix defined on http://www.rabbitmq.com/uri-spec.htmltype 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: darwingoarch: amd64pkg: go-demo/testexample/uricpu: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHzBenchmarkUri-8           2041880               579.2 ns/opPASSok      go-demo/testexample/uri 2.075s

基准测试后果意味着基准测试通过。循环运行 2041880 次,每个循环速度为 579.2 纳秒。