百木园-与人分享,
就是让自己快乐。

golang单元测试一(简单函数测试)

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:pass@host:10000/vhost\",
	username: \"user\",
	password: \"pass\",
	host:     \"host\",
	port:     10000,
	vhost:    \"vhost\",
	canon:    \"amqp://user:pass@host: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:pass@host: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:pass@host:10000/vhost\",
		username: \"user\",
		password: \"pass\",
		host:     \"host\",
		port:     10000,
		vhost:    \"vhost\",
		canon:    \"amqp://user:pass@host: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://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://: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:pass@host:10000/vhost\",
		username: \"user\",
		password: \"pass\",
		host:     \"host\",
		port:     10000,
		vhost:    \"vhost\",
		canon:    \"amqp://user:pass@host: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://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://: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: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)
	}
}

然后执行:

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

我们浏览器打开这个文件,会看到下面这个界面,不要太爽:
wp-content/uploads/2022/10/https://www.173top.cn/wp-content/uploads/2022/10/1666690415-20221025093335-6357ad6fe35ea.png

红色的就是代表我们测试没有覆盖到的。只需要丰富下测试代码,就可以做到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:pass@host:10000/vhost\",
	username: \"user\",
	password: \"pass\",
	host:     \"host\",
	port:     10000,
	vhost:    \"vhost\",
	canon:    \"amqp://user:pass@host: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 纳秒。


来源:https://www.cnblogs.com/liuyuede123/p/16799009.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » golang单元测试一(简单函数测试)

相关推荐

  • 暂无文章