Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Golang入门指南 - 测试 #22

Open
xpzouying opened this issue Nov 15, 2020 · 0 comments
Open

Golang入门指南 - 测试 #22

xpzouying opened this issue Nov 15, 2020 · 0 comments
Labels

Comments

@xpzouying
Copy link
Owner

Golang测试

本章节介绍在Golang中如何进行测试。

1、单元测试

以一个计算器示例demo。

计算器支持4种操作,加减乘除。

// Operation 支持的操作
type Operation int

// 操作列表
const (
	OpAdd Operation = iota
	OpSub
	OpMul
	OpDiv
)

// Calculator 计算器
type Calculator struct{}

// Do 计算机进行计算
func (c Calculator) Do(op Operation, a, b int) (int, error) {
	switch op {
	case OpAdd:
		return c.add(a, b), nil
	case OpSub:
		return c.sub(a, b), nil
	case OpMul:
		return c.mul(a, b), nil
	case OpDiv:
		return c.div(a, b)
	default:
	}

	// unknown op?
	return 0, errors.New("unknown error")
}

func (Calculator) add(a, b int) int { return a + b }

func (Calculator) sub(a, b int) int { return a - b }

func (Calculator) mul(a, b int) int { return a * b }

func (Calculator) div(a, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("invalid b: zero")
	}

	return a / b, nil
}

暂时不考虑溢出的情况。围绕该计算器编写响应的测试用例代码。

1.1、单元测试用例

测试用例的规则为:

测试文件以*_test.go命名,与正常的代码文件放在同一个package里面。

Xxx不能以小写字母开头。

func TestXxx(*testing.T)

测试用例

func TestAdd(t *testing.T) {
	c := Calculator{}

	a, b := 1, 2
	op := OpAdd

	res, err := c.Do(op, a, b)
	if err != nil {
		t.Errorf("do error: %v", err)
	}

	want := 3
	if res != want {
		t.Errorf("calculater error: a=%d,b=%d,res=%d,want=%d", a, b, res, want)
	}
}

1.2、运行单元测试

运行测试用例。

go test

go test -v .

go test -v -run="TestAdd"
# 与上面一样
go test -v -run="Add"

1.3、单元测试覆盖

go test -cover查看当前的测试用例覆盖。

go test -cover
➜  1_testing (go-testing) ✗ go test -cover       
PASS
coverage: 25.0% of statements
ok      github.com/xpzouying/golang-notes/docs/go_testing/demo/1_testing        0.002s

手动生成

1、生成profile数据文件:使用-coverprofile

➜  1_testing (go-testing) ✗ go test -coverprofile=coverage.out
PASS
coverage: 25.0% of statements
ok      github.com/xpzouying/golang-notes/docs/go_testing/demo/1_testing        0.002s

2、转换为html文件:使用-html

➜  1_testing (go-testing) ✗ go tool cover -html=coverage.out  
HTML output written to /tmp/cover018342743/coverage.html

image

使用vscode查看覆盖

MacOS下按快捷键:command+shift+P,搜索命令:go covergo: toggle test coverage

image

1.4、增加更多的单元测试

使用TDD模式

安装goconvey工具。

go get github.com/smartystreets/goconvey

# 启动服务,默认监听在:8080端口
goconvey

image

增加更多的测试用例

重复大量的代码,覆盖各种边界值,特殊条件等等。

使用表格法:table-driven

使用表格法,可以避免重复的业务逻辑代码,更加关注测试数据和异常边界值。

func TestAllInOneTable(t *testing.T) {
	ts := []struct {
		Op      Operation
		A       int
		B       int
		WantRes int
		WantErr error
	}{
		{Op: OpAdd, A: 1, B: 2, WantRes: 3, WantErr: nil},
		{Op: OpSub, A: 5, B: 3, WantRes: 2, WantErr: nil},
		{Op: OpMul, A: 5, B: 3, WantRes: 15, WantErr: nil},
		{Op: OpDiv, A: 15, B: 3, WantRes: 5, WantErr: nil},
		{Op: OpDiv, A: 15, B: 0, WantRes: 0, WantErr: ErrInvalidB},
	}

	c := Calculator{}

	for _, tc := range ts {
		a, b := tc.A, tc.B
		op := tc.Op
		want := tc.WantRes

		res, err := c.Do(op, a, b)
		if err != tc.WantErr {
			t.Errorf("do error: %v", err)
			continue
		}

		if res != want {
			t.Errorf("calculater error: a=%d,b=%d,res=%d,want=%d", a, b, res, want)
		}
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant