Go的自动化测试

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/benben_2015/article/details/82812032

自动化测试,是在预设条件下运行系统或应用程序,评估运行结果,预先条件包括正常条件和异常条件。Go本身提供了一套轻量级的测试框架,相对低级,但不过还是有效的。它依赖一个go test测试命令,和一组按照约定方式编写的测试函数,符合规则的测试代码会在运行测试时被自动识别并执行。但是这些文件是不会被普通的Go编译器编译,所以当将应用部署到生产环境时,它们不会被部署。

测试规则

文件命名与放置规则

  1. 测试源文件名应是_test结尾的go文件,例如:add_test.go
  2. 测试代码和业务代码是分开的,但两者应该位于同一包下;
  3. 测试源文件所在的包应该位于$GOPATH/src目录下;
  4. 测试文件必须导入"testing"包;

在Go中,凡是以_或者.符号作为文件名的首字母时,该文件都会被构建工具忽略掉。以_test.go结尾的测试文件,将会被编译为单独的包,然后将其链接到主测试二进制文件。
go工具还会忽略名为testdata的目录,使其可以保存测试所需的辅助数据。

测试函数命名规则

测试文件包括三种函数:测试函数、基准测试函数和例子函数。测试函数用于测试程序的一些逻辑行为是否正确的函数,在命名时应该以Test为前缀,例如func TestAbcde(t *testing.T)。基准测试用于衡量一些函数的性能,是以Benchmark为函数名前缀的函数,例如func BenchmarkAbcde(b *testing.B)。例子函数用来说明函数(变量,常量等)如何使用,以Example为函数名前缀的函数,例如:

func ExamplePrintln(){
    Println("The output of\nthis example.")
    //Output: The output of
    //this example.
}

go test命令

go test命令会自动测试导入路径命名的包并缓存测试结果,根据测试的结果和预先设定的是否匹配,会返回PASSFAIL。它的用法:go test [build/test参数] [包名],它有两种不同的模式:本地目录模式和包列表模式。仅在包列表模式下,go test会缓存成功的包测试结果以避免不必要的重复运行已经通过的测试。当测试的结果可以从缓存中恢复,go test将会重新显示以前的输出而不是再次运行测试二进制文件

本地目录模式

这种模式是在没有包参数的情况下,调用go test时发生,例如:go testgo test -v。在此模式下,go test会编译当前目录中的包和测试文件,然后运行生成的二进制文件。这种模式下,缓存是被禁用的。测试完成后,go test会打印结果摘要,逐行显示测试状态,包名称和已用的时间。

包列表模式

在调用go test时传入显式包参数,例如:go test mathgo test ./...,或者go test .等。在此模式下,go test会编译和测试命令行中列出的每一个包。如果一个包测试通过,go test只打印成功摘要,但如果测试失败,则会打印完整的信息。如果你传入参数-bench-v标志,那么go test将会打印完整的输出,即使是通过测试的包。第一个参数是当有基准测试函数时使用,第二种就是平常的测试函数就行。

显式禁用缓存的惯用方法是使用-count=1

go test参数

-bench [正则表达式]:仅运行与正则表达式匹配的基准,默认情况下,不运行基准测试。如果要运行所有的基准测试函数,使用-bench .或者-bench=.
-benchtime [时间]:表示运行多长时间的基准测试,默认值为1秒。例如:-benchtime 1h30s
-count n:运行每个测试和基准多少次,默认为1,如果设置了-cpu,则为每个GOMAXPROCS运行n次,例子函数总是运行一次。
-cover:启用覆盖率分析,由于覆盖率通过在编译之前注释源代码来工作,因此启用覆盖率的编译和测试失败,可能会出现报告与原始文件行号不对应的情况。
-covermode set,count,atomic:为正在测试的包设置覆盖率分析模式,除非启用-race,否则默认为set,在这种情况下它是原子的。

  • set,布尔值,表示这句声明是否有效
  • count,int类型,这句声明运行多少次
  • atomic,int类型,在多线程测试中使用,原子操作。

-coverpkg pattern1,pattern2,pattern3:将每个测试中的覆盖率分析应用于模式匹配的包,默认情况下,每个测试仅分析正在测试的包。
-cpu 1,2,4:指定应为其执行测试或基准测试的GOMAXPROCS的值的列表,默认值是GOMAXPROCS的当前值。
-failfast:表示在第一次测试失败后不要开始新的测试。
-list [正则表达式]:只是列出与正则表达式匹配的测试、基准测试或例子,不会运行任何测试。
-parallel n:表示运行的最大测试数,默认情况下,它设置为GOMAXPROCS的值。
-run [正则表达式]:仅仅运行与正则表达式匹配的那些测试和例子,匹配时可能父项也会运行,例如:-run = X/Y,匹配运行所有与X匹配的测试的结果,即使没有匹配到子测试。
-timeout [时间]:如果测试文件运行的时间超过设置的时间,就会出现panic。如果设置的时间为0,则表示timeout不可用。默认是10分钟。
-v:会打印详细的测试结果,即使是在测试成功的情况。

testing包

提供有关Go自动化测试的支持,它与go test命令一起使用。

// TB 是类型T和B的接口.
type TB interface {
	Error(args ...interface{})  //Fail+Log
	Errorf(format string, args ...interface{})
	Fail()          //标记失败,但继续执行该测试函数
	FailNow()       //失败,立即停止当前测试函数
	Failed() bool
	Fatal(args ...interface{})  //FailNow+Log
	Fatalf(format string, args ...interface{})
	Log(args ...interface{})    //输出信息,仅在失败或-v参数时输出
	Logf(format string, args ...interface{})
	Name() string
	Skip(args ...interface{})
	SkipNow()                   //跳过当前测试函数
	Skipf(format string, args ...interface{})
	Skipped() bool
	Helper()
	private()
}

例子

1.在你的$GOPATH/src目录下,创建一个目录,例如:mytest文件夹。
2.创建一个main文件,写入业务代码。例如下面将0加到n的函数进行测试:

package main

func addNum(n int) (result int) {
	for i := 0; i <= n; i++ {
		result = result + i
	}
	return
}

3.创建测试文件,文件名以_test.go结尾,例如:main_test.go

package main

import (
	"testing"
)

func TestAddNum(t *testing.T) {
	if addNum(100) != 5050 {
		t.Fatal("addNum error!")
	}
}

4.在命令行里,直接输入go test,运行当前包的所有测试文件。或者运行go test mytest,只测试mytest包的测试文件。
本地目录方式运行时的返回结果:

PASS
ok      mytest  0.421s

包列表模式运行的返回结果:ok mytest 0.138s
5.在main.go文件中,添加基准测试函数。

package main

import (
	"testing"
)

func TestAddNum(t *testing.T) {
	if addNum(100) != 5050 {
		t.Fatal("addNum error!")
	}
}

func BenchmarkAddNum(b *testing.B) {
	for i := 0; i < b.N; i++ {
		if addNum(100) != 5050 {
			b.Fatal("addNum")
		}
	}
}

6.运行基准测试,go test -bench .,默认情况下,go test不会执行性能测试函数。性能测试需要运行足够多的次数才能计算单次执行平均时间。

goos: windows
goarch: amd64
pkg: mytest
BenchmarkAddNum-4       10000000               187 ns/op
PASS
ok      mytest  2.522s

报告显示执行addNum函数花费的平均时间是2.522s,执行了10000000次,每282ns的速度运行一次循环。因为基准测试驱动器并不知道每个基准测试函数运行所花的时间,因此它会在真正运行基准测试前先试用较小的N来运行测试,估算基准测试函数所需要的时间,然后推断一个较大的时间保证稳定的测量结果。
循环在基准测试函数内实现,而不是放在基准测试框架内实现,这样可以让每个基准测试函数有机会在循环启动前执行初始化代码,这样并不会显著影响每次迭代的平均运行时间。
如果在运行基准测试之前需要一些费事的设置,则可能会重置计时器。例如:

func BenchmarkAddNum(b *testing.B) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if addNum(100) != 5050 {
			b.Fatal("addNum")
		}
	}
}

参考文章:

  1. Package testing
  2. Command go

猜你喜欢

转载自blog.csdn.net/benben_2015/article/details/82812032
今日推荐