Go-单元测试详解与代码

目录golang

概述运维

Go的单元测试ide

基础知识函数

快速入门性能

进阶单元测试

单个文件的测试测试

单个函数的测试ui

单元测试覆盖率日志

参考code


概述

常言道,不会测试的程序猿不是好的产品经理!!!如今愈来愈多测试和运维的工做也须要研发来作了,本篇文章就来说讲Go的单元测试。

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。简单说,就是将测试用例的运行结果与预期结果进行比较。

Go的单元测试

基础知识

Go有testing测试包,配合go test命令可以进行单元测试。

  1. 测试文件以_test.go结尾
  2. 在包目录内,全部以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。
  3. _test.go文件包含TestXxx函数
  4. 形参类型必须为*test.T
  5. PASS表示测试用例运行成功,FAIL表示失败

我的经常使用Fatalf,这里就来具体说一下,其余函数见参考的连接。

func (c *T) Logf(format string, args ...interface{})

Log 使用与 Printf 相同的格式化语法对它的参数进行格式化,而后将格式化后的文本记录到错误日志里面。 若是输入的格式化文本最末尾没有出现新行,那么将一个新行添加到格式化后的文本末尾。

1)对于测试来讲,Logf 产生的格式化文本只会在测试失败或者设置了 -test.v 标志的状况下被打印出来;

2)对于基准测试来讲,为了不 -test.v 标志的值对测试的性能产生影响,Logf 产生的格式化文本总会被打印出来

func (c *T) FailNow()

将当前测试标识为失败并中止执行该测试,在此以后,测试过程将在下一个测试或者下一个基准测试中继续。

FailNow 必须在运行测试函数或者基准测试函数的 goroutine 中调用,而不能在测试期间建立的 goroutine 中调用。调用 FailNow 不会致使其余 goroutine 中止。

func (c *T) Fatalf(format string, args ...interface{})

调用 Fatalf 至关于在调用 Logf 以后调用 FailNow 。 

快速入门

项目结构

learnGo
└── main
    ├── compute.go
    └── compute_test.go

compute.go

package main

import "errors"

func div(a,b int) (int,error) {
	if b != 0{
		return a/b,nil
	} else{
		return 0,errors.New("b is 0")
	}
}

compute_test.go

package main

import "testing"

func TestDiv(t *testing.T)  {
	res,_ := div(4,2)
	want := 2
	if res != want{
		t.Fatalf("期待:%d ,实际结果:%d",want,res)
	}
}

main目录下运行

go test -v

结果以下:

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
PASS
ok      learnGo/main    0.457s

以上咱们就针对main包的compute.go文件进行了单元测试。

进阶

查看更多的选项,可以使用

go help test

go help testflag

单个文件的测试

咱们在main包中再添加str.go及str_test.go

str.go

package main

func getSub(str string,start,end int) string {
	// 左闭右闭
	if 0<=start&&start<end&&end<=len(str){
		return str[start:end]
	}else{
		return ""
	}
}

str_test.go

package main

import "testing"

func TestGetSub(t *testing.T)  {
	astr := "lady_killer9"
	// 包含开头
	res1 := getSub(astr,0,4)
	want1 := "lady"
	// 包含结尾
	res2 := getSub(astr,4,len(astr))
	want2 := "_killer9"
	// 范围错误
	res3 := getSub(astr,1,len(astr)+1)
	want3 := ""
	if res1 != want1{
		t.Errorf("指望:%s,实际结果:%s",want1,res1)
	}
	if res2 != want2{
		t.Errorf("指望:%s,实际结果:%s",want2,res2)
	}
	if res3 != want3{
		t.Errorf("指望:%s,实际结果:%s",want3,res3)
	}
}

运行 go test -v,获得结果以下

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      learnGo/main    0.446s

go test会运行全部的单元测试,有时候咱们只想测试某个文件

若是只是运行一个测试文件,可添加参数

go test -v 测试文件 源文件

运行go test -v str_test.go str.go, 结果以下:

=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      command-line-arguments  0.619s

单个函数的测试

咱们在compute.go中添加

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

在compute_test.go中添加

func TestAdd(t *testing.T)  {
	a,b:=3,4
	res := add(a,b)
	want := 7
	if res != want{
		t.Fatalf("期待:%d,实际结果:%d",want,res)
	}
}

因为对div函数未作改动,只想测试add函数,可使用参数-test.run指定测试函数

go test -v -test.run 测试函数

运行 go test -v -test.run TestAdd 结果以下:

=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      learnGo/main    0.836s

单元测试覆盖率

测试应该全面,达到100%。

可使用-cover参数

go test -cover

结果以下:

PASS
coverage: 85.7% of statements
ok      learnGo/main    0.505s

能够看到,测试的并不全面,指定测试文件来查看。

go test -cover compute_test.go compute.go

ok      command-line-arguments  0.314s  coverage: 75.0% of statements

观察发现,咱们缺乏了b为0的分支,修改TestDiv函数为

func TestDiv(t *testing.T)  {
	res,_ := div(4,2)
	want := 2
	if res != want{
		t.Fatalf("期待:%d,实际结果:%d",want,res)
	}
	res,_ = div(3,0)
	want = 0
	if res != want{
		t.Fatalf("期待:%d,实际结果:%d",want,res)
	}
}

测试后再看覆盖率,结果以下

PASS
coverage: 100.0% of statements
ok      learnGo/main    0.306s

做为开发,基本的单元测试就能够了,还能够去了解基准测试、性能测试、压力测试、黑盒测试等。

参考

Go标准库-testing

相关文章
相关标签/搜索