Do not write the test development is not a good programmer. I personally advocate TDD (Test Driven Development), but unfortunately is the programmers are not very concerned about this part of the test. Under this article describes how to do unit testing and benchmarking in the Go language.
go test tool
Go language tests depend on go test
command. Writing tests and writing code for common Go process is similar, we do not need to learn new grammar rules or tools.
go test command is a test code in accordance with certain conventions and organizations drivers. In the package directory, all with _test.go
the source code file extensions are go test
part of the test will not be go build
compiled into the final executable file.
In the *_test.go
three types of functions, the function test unit, test function, and sample function file.
Types of | format | effect |
---|---|---|
Test function | Function name prefix is Test | Some behavioral testing program logic is correct |
Benchmark functions | Benchmark function name prefix | Performance test function |
Sample Function | Function name prefix Example | Provide an example for a document |
go test
Command will traverse all *_test.go
files comply with the above function naming rules, and then generates a temporary package for the main function call the appropriate test, then build and run, report test results, final clean-up test generated temporary files.
Test function
Format function test
Each test must import function testing
package, the basic format of the test function (Signed) as follows:
func TestName(t *testing.T){
// ...
}
Name of the test function must Test
begin with optional suffix names must begin with a capital letter, a few examples:
func TestAdd(t *testing.T){ ... }
func TestSum(t *testing.T){ ... }
func TestLog(t *testing.T){ ... }
In which the parameters t
for reporting test failures and additional log information. testing.T
The method has the following:
func (c *T) Error(args ...interface{})
func (c *T) Errorf(format string, args ...interface{})
func (c *T) Fail()
func (c *T) FailNow()
func (c *T) Failed() bool
func (c *T) Fatal(args ...interface{})
func (c *T) Fatalf(format string, args ...interface{})
func (c *T) Log(args ...interface{})
func (c *T) Logf(format string, args ...interface{})
func (c *T) Name() string
func (t *T) Parallel()
func (t *T) Run(name string, f func(t *T)) bool
func (c *T) Skip(args ...interface{})
func (c *T) SkipNow()
func (c *T) Skipf(format string, args ...interface{})
func (c *T) Skipped() bool
Test function example
Like cell is the basic unit of our body, a software program is made up of many components that make up the unit. Cell assembly may be a function, structure, process, and end user may rely on something arbitrary. In short we need to ensure that these components are capable of normal operation. Some unit testing using various methods to test cell assembly procedures, it will be compared with the results expected output.
Next, we define a split
package, the package defines a Split
function, specifically implemented as follows:
// split/split.go
package split
import "strings"
// split package with a single split function.
// Split slices s into all substrings separated by sep and
// returns a slice of the substrings between those separators.
func Split(s, sep string) (result []string) {
i := strings.Index(s, sep)
for i > -1 {
result = append(result, s[:i])
s = s[i+1:]
i = strings.Index(s, sep)
}
result = append(result, s)
return
}
In the current directory, we create a split_test.go
test file and define a test function as follows:
// split/split_test.go
package split
import (
"reflect"
"testing"
)
func TestSplit(t *testing.T) { // 测试函数名必须以Test开头,必须接收一个*testing.T类型参数
got := Split("a:b:c", ":") // 程序输出的结果
want := []string{"a", "b", "c"} // 期望的结果
if !reflect.DeepEqual(want, got) { // 因为slice不能比较直接,借助反射包中的方法比较
t.Errorf("excepted:%v, got:%v", want, got) // 测试失败输出错误提示
}
}
At this time, split
the package files are as follows:
split $ ls -l
total 16
-rw-r--r-- 1 nickchen121 staff 408 4 29 15:50 split.go
-rw-r--r-- 1 nickchen121 staff 466 4 29 16:04 split_test.go
In split
the package path, execute go test
the command, the output can be seen as follows:
split $ go test
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.005s
A test case a little thin, we'll write a test example of the use of multiple character strings cut in split_test.go
to add test functions as follows:
func TestMoreSplit(t *testing.T) {
got := Split("abcd", "bc")
want := []string{"a", "d"}
if !reflect.DeepEqual(want, got) {
t.Errorf("excepted:%v, got:%v", want, got)
}
}
Rerun go test
command, the output results are as follows:
split $ go test
--- FAIL: TestMultiSplit (0.00s)
split_test.go:20: excepted:[a d], got:[a cd]
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
This time, our test failed. We can go test
add the command -v
parameter, the function name and view the test run time:
split $ go test -v
=== RUN TestSplit
--- PASS: TestSplit (0.00s)
=== RUN TestMoreSplit
--- FAIL: TestMoreSplit (0.00s)
split_test.go:21: excepted:[a d], got:[a cd]
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.005s
This time we can clearly see that TestMoreSplit
this test does not succeed. You can also at go test
add the command -run
parameter, which corresponds to a regular expression, the function will be tested only on the function name match is go test
command execution.
split $ go test -v -run="More"
=== RUN TestMoreSplit
--- FAIL: TestMoreSplit (0.00s)
split_test.go:21: excepted:[a d], got:[a cd]
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
Now we come back to solve the problems of our program. It is clear that our original split
function does not take into account the situation sep multiple characters, we have to fix this Bug:
package split
import "strings"
// split package with a single split function.
// Split slices s into all substrings separated by sep and
// returns a slice of the substrings between those separators.
func Split(s, sep string) (result []string) {
i := strings.Index(s, sep)
for i > -1 {
result = append(result, s[:i])
s = s[i+len(sep):] // 这里使用len(sep)获取sep的长度
i = strings.Index(s, sep)
}
result = append(result, s)
return
}
This time let's test our program. Note that when we modify our code not only execute those failed test function, we should complete the run all the tests, ensures that no code changes introduced new problems.
split $ go test -v
=== RUN TestSplit
--- PASS: TestSplit (0.00s)
=== RUN TestMoreSplit
--- PASS: TestMoreSplit (0.00s)
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
This time we have passed the test.
Test Group
We now want to test the split
function of support for the Chinese string, this time we can then write a TestChineseSplit
test function, but we can also add more test case follows a more friendly way.
func TestSplit(t *testing.T) {
// 定义一个测试用例类型
type test struct {
input string
sep string
want []string
}
// 定义一个存储测试用例的切片
tests := []test{
{input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
{input: "a:b:c", sep: ",", want: []string{"a:b:c"}},
{input: "abcd", sep: "bc", want: []string{"a", "d"}},
{input: "沙河有沙又有河", sep: "沙", want: []string{"河有", "又有河"}},
}
// 遍历切片,逐一执行测试用例
for _, tc := range tests {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("excepted:%v, got:%v", tc.want, got)
}
}
}
Through the above code to fit together the multiple test cases, execution again go test
command.
split $ go test -v
=== RUN TestSplit
--- FAIL: TestSplit (0.00s)
split_test.go:42: excepted:[河有 又有河], got:[ 河有 又有河]
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
Our test there is a problem, look carefully test print failure message: excepted:[河有 又有河], got:[ 河有 又有河]
You will find that [ 河有 又有河]
there are two obvious empty string, in which case highly recommend using %#v
formatting way.
We modify test cases under section formatted output an error message:
func TestSplit(t *testing.T) {
...
for _, tc := range tests {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("excepted:%#v, got:%#v", tc.want, got)
}
}
}
In this case run go test
the command you can see the obvious message:
split $ go test -v
=== RUN TestSplit
--- FAIL: TestSplit (0.00s)
split_test.go:42: excepted:[]string{"河有", "又有河"}, got:[]string{"", "河有", "又有河"}
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
Subtest
It looks so good, but if you test more, we are not seeing a way out which specific test case failed. We might think of the following solutions:
func TestSplit(t *testing.T) {
type test struct { // 定义test结构体
input string
sep string
want []string
}
tests := map[string]test{ // 测试用例使用map存储
"simple": {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
"wrong sep": {input: "a:b:c", sep: ",", want: []string{"a:b:c"}},
"more sep": {input: "abcd", sep: "bc", want: []string{"a", "d"}},
"leading sep": {input: "沙河有沙又有河", sep: "沙", want: []string{"河有", "又有河"}},
}
for name, tc := range tests {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("name:%s excepted:%#v, got:%#v", name, tc.want, got) // 将测试用例的name格式化输出
}
}
}
The above approach is the ability to solve problems. Meanwhile Go1.7 + added a sub-test, we can use follows t.Run
the implementation of sub-tests:
func TestSplit(t *testing.T) {
type test struct { // 定义test结构体
input string
sep string
want []string
}
tests := map[string]test{ // 测试用例使用map存储
"simple": {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
"wrong sep": {input: "a:b:c", sep: ",", want: []string{"a:b:c"}},
"more sep": {input: "abcd", sep: "bc", want: []string{"a", "d"}},
"leading sep": {input: "沙河有沙又有河", sep: "沙", want: []string{"河有", "又有河"}},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) { // 使用t.Run()执行子测试
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("excepted:%#v, got:%#v", tc.want, got)
}
})
}
}
At this point we then execute go test
the command will be able to see more clearly the contents of the output:
split $ go test -v
=== RUN TestSplit
=== RUN TestSplit/leading_sep
=== RUN TestSplit/simple
=== RUN TestSplit/wrong_sep
=== RUN TestSplit/more_sep
--- FAIL: TestSplit (0.00s)
--- FAIL: TestSplit/leading_sep (0.00s)
split_test.go:83: excepted:[]string{"河有", "又有河"}, got:[]string{"", "河有", "又有河"}
--- PASS: TestSplit/simple (0.00s)
--- PASS: TestSplit/wrong_sep (0.00s)
--- PASS: TestSplit/more_sep (0.00s)
FAIL
exit status 1
FAIL github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
This time we want to test the bug fixes back:
func TestSplit(t *testing.T) {
...
tests := map[string]test{ // 测试用例使用map存储
"simple": {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
"wrong sep": {input: "a:b:c", sep: ",", want: []string{"a:b:c"}},
"more sep": {input: "abcd", sep: "bc", want: []string{"a", "d"}},
"leading sep": {input: "沙河有沙又有河", sep: "沙", want: []string{"", "河有", "又有河"}},
}
...
}
We all know that can -run=RegExp
be specified to run test cases, can also /
sub to specify test cases to run, for example: go test -v -run=Split/simple
only run simple
the corresponding sub-test.
Test coverage
Test coverage is the percentage of your code is covered by the test suite. Usually we use are statement coverage, that is, the ratio of the code to run at least once in the total code test.
Go provides built-in function to check your code coverage. We can use go test -cover
to view the test coverage. E.g:
split $ go test -cover
PASS
coverage: 100.0% of statements
ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.005s
From the above results can be seen in our test cases covering 100% of the code.
Go also offers an additional -coverprofile
parameter for output to a file associated with record coverage information. E.g:
split $ go test -cover -coverprofile=c.out
PASS
coverage: 100.0% of statements
ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.005s
The above command will output coverage information related to the current folder the following c.out
files, and then we execute go tool cover -html=c.out
, use the cover
tools to handle record information generated, the command will open the local browser window generates a HTML report. Each block of statements above figure indicates green flag is covered, while red indicates not covered.
Benchmarks
Benchmark function format
Benchmark is a method for detecting program performance under certain workloads. The basic format of benchmarks are as follows:
func BenchmarkName(b *testing.B){
// ...
}
In benchmark Benchmark
prefix requires a *testing.B
parameter of type B, the benchmark must be performed b.N
twice, only the control of such a test, b.N
the value of the system adjusted to the actual situation, thereby ensuring stability test. testing.B
The method has the following:
func (c *B) Error(args ...interface{})
func (c *B) Errorf(format string, args ...interface{})
func (c *B) Fail()
func (c *B) FailNow()
func (c *B) Failed() bool
func (c *B) Fatal(args ...interface{})
func (c *B) Fatalf(format string, args ...interface{})
func (c *B) Log(args ...interface{})
func (c *B) Logf(format string, args ...interface{})
func (c *B) Name() string
func (b *B) ReportAllocs()
func (b *B) ResetTimer()
func (b *B) Run(name string, f func(b *B)) bool
func (b *B) RunParallel(body func(*PB))
func (b *B) SetBytes(n int64)
func (b *B) SetParallelism(p int)
func (c *B) Skip(args ...interface{})
func (c *B) SkipNow()
func (c *B) Skipf(format string, args ...interface{})
func (c *B) Skipped() bool
func (b *B) StartTimer()
func (b *B) StopTimer()
Benchmark example
We split the package Split
to write the reference function tests are as follows:
func BenchmarkSplit(b *testing.B) {
for i := 0; i < b.N; i++ {
Split("沙河有沙又有河", "沙")
}
}
Benchmark and will not default execution, need to increase the -bench
parameters, we executed through go test -bench=Split
the implementation of benchmarking command, the output results are as follows:
split $ go test -bench=Split
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/split
BenchmarkSplit-8 10000000 203 ns/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 2.255s
Which BenchmarkSplit-8
represents the benchmark for the Split function, the digital 8
representation GOMAXPROCS
value, this is very important for concurrent benchmark. 10000000
And 203ns/op
represent each call Split
function time-consuming 203ns
, the result is 10000000
the average of invocation.
We can also add benchmark -benchmem
parameters to obtain statistical data memory allocation.
split $ go test -bench=Split -benchmem
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/split
BenchmarkSplit-8 10000000 215 ns/op 112 B/op 3 allocs/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 2.394s
Wherein 112 B/op
represents each operation allocated 112 bytes of memory, 3 allocs/op
it said each operation conducted three memory allocation. We will be our Split
function optimization as follows:
func Split(s, sep string) (result []string) {
result = make([]string, 0, strings.Count(s, sep)+1)
i := strings.Index(s, sep)
for i > -1 {
result = append(result, s[:i])
s = s[i+len(sep):] // 这里使用len(sep)获取sep的长度
i = strings.Index(s, sep)
}
result = append(result, s)
return
}
这一次我们提前使用make函数将result初始化为一个容量足够大的切片,而不再像之前一样通过调用append函数来追加。我们来看一下这个改进会带来多大的性能提升:
split $ go test -bench=Split -benchmem
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/split
BenchmarkSplit-8 10000000 127 ns/op 48 B/op 1 allocs/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 1.423s
这个使用make函数提前分配内存的改动,减少了2/3的内存分配次数,并且减少了一半的内存分配。
性能比较函数
上面的基准测试只能得到给定操作的绝对耗时,但是在很多性能问题是发生在两个不同操作之间的相对耗时,比如同一个函数处理1000个元素的耗时与处理1万甚至100万个元素的耗时的差别是多少?再或者对于同一个任务究竟使用哪种算法性能最佳?我们通常需要对两个不同算法的实现使用相同的输入来进行基准比较测试。
性能比较函数通常是一个带有参数的函数,被多个不同的Benchmark函数传入不同的值来调用。举个例子如下:
func benchmark(b *testing.B, size int){/* ... */}
func Benchmark10(b *testing.B){ benchmark(b, 10) }
func Benchmark100(b *testing.B){ benchmark(b, 100) }
func Benchmark1000(b *testing.B){ benchmark(b, 1000) }
例如我们编写了一个计算斐波那契数列的函数如下:
// fib.go
// Fib 是一个计算第n个斐波那契数的函数
func Fib(n int) int {
if n < 2 {
return n
}
return Fib(n-1) + Fib(n-2)
}
我们编写的性能比较函数如下:
// fib_test.go
func benchmarkFib(b *testing.B, n int) {
for i := 0; i < b.N; i++ {
Fib(n)
}
}
func BenchmarkFib1(b *testing.B) { benchmarkFib(b, 1) }
func BenchmarkFib2(b *testing.B) { benchmarkFib(b, 2) }
func BenchmarkFib3(b *testing.B) { benchmarkFib(b, 3) }
func BenchmarkFib10(b *testing.B) { benchmarkFib(b, 10) }
func BenchmarkFib20(b *testing.B) { benchmarkFib(b, 20) }
func BenchmarkFib40(b *testing.B) { benchmarkFib(b, 40) }
运行基准测试:
split $ go test -bench=.
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/fib
BenchmarkFib1-8 1000000000 2.03 ns/op
BenchmarkFib2-8 300000000 5.39 ns/op
BenchmarkFib3-8 200000000 9.71 ns/op
BenchmarkFib10-8 5000000 325 ns/op
BenchmarkFib20-8 30000 42460 ns/op
BenchmarkFib40-8 2 638524980 ns/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/fib 12.944s
这里需要注意的是,默认情况下,每个基准测试至少运行1秒。如果在Benchmark函数返回时没有到1秒,则b.N的值会按1,2,5,10,20,50,…增加,并且函数再次运行。
最终的BenchmarkFib40只运行了两次,每次运行的平均值只有不到一秒。像这种情况下我们应该可以使用-benchtime
标志增加最小基准时间,以产生更准确的结果。例如:
split $ go test -bench=Fib40 -benchtime=20s
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/fib
BenchmarkFib40-8 50 663205114 ns/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/fib 33.849s
这一次BenchmarkFib40
函数运行了50次,结果就会更准确一些了。
使用性能比较函数做测试的时候一个容易犯的错误就是把b.N
作为输入的大小,例如以下两个例子都是错误的示范:
// 错误示范1
func BenchmarkFibWrong(b *testing.B) {
for n := 0; n < b.N; n++ {
Fib(n)
}
}
// 错误示范2
func BenchmarkFibWrong2(b *testing.B) {
Fib(b.N)
}
重置时间
b.ResetTimer
之前的处理不会放到执行时间里,也不会输出到报告中,所以可以在之前做一些不计划作为测试报告的操作。例如:
func BenchmarkSplit(b *testing.B) {
time.Sleep(5 * time.Second) // 假设需要做一些耗时的无关操作
b.ResetTimer() // 重置计时器
for i := 0; i < b.N; i++ {
Split("沙河有沙又有河", "沙")
}
}
并行测试
func (b *B) RunParallel(body func(*PB))
会以并行的方式执行给定的基准测试。
RunParallel
会创建出多个goroutine
,并将b.N
分配给这些goroutine
执行, 其中goroutine
数量的默认值为GOMAXPROCS
。用户如果想要增加非CPU受限(non-CPU-bound)基准测试的并行性, 那么可以在RunParallel
之前调用SetParallelism
。RunParallel
通常会与-cpu
标志一同使用。
func BenchmarkSplitParallel(b *testing.B) {
// b.SetParallelism(1) // 设置使用的CPU数
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Split("沙河有沙又有河", "沙")
}
})
}
执行一下基准测试:
split $ go test -bench=.
goos: darwin
goarch: amd64
pkg: github.com/Q1mi/studygo/code_demo/test_demo/split
BenchmarkSplit-8 10000000 131 ns/op
BenchmarkSplitParallel-8 50000000 36.1 ns/op
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 3.308s
还可以通过在测试命令后添加-cpu
参数如go test -bench=. -cpu 1
来指定使用的CPU数量。
Setup与TearDown
测试程序有时需要在测试之前进行额外的设置(setup)或在测试之后进行拆卸(teardown)。
TestMain
通过在*_test.go
文件中定义TestMain
函数来可以在测试之前进行额外的设置(setup)或在测试之后进行拆卸(teardown)操作。
如果测试文件包含函数:func TestMain(m *testing.M)
那么生成的测试会先调用 TestMain(m),然后再运行具体测试。TestMain
运行在主goroutine
中, 可以在调用 m.Run
前后做任何设置(setup)和拆卸(teardown)。退出测试的时候应该使用m.Run
的返回值作为参数调用os.Exit
。
一个使用TestMain
来设置Setup和TearDown的示例如下:
func TestMain(m *testing.M) {
fmt.Println("write setup code here...") // 测试之前的做一些设置
// 如果 TestMain 使用了 flags,这里应该加上flag.Parse()
retCode := m.Run() // 执行测试
fmt.Println("write teardown code here...") // 测试之后做一些拆卸工作
os.Exit(retCode) // 退出测试
}
需要注意的是:在调用TestMain
时, flag.Parse
并没有被调用。所以如果TestMain
依赖于command-line标志 (包括 testing 包的标记), 则应该显示的调用flag.Parse
。
子测试的Setup与Teardown
Sometimes we may need to set for each test set Setup and Teardown, there may need to test settings for each sub-Setup and Teardown. Here we define two functions tool functions as follows:
// 测试集的Setup与Teardown
func setupTestCase(t *testing.T) func(t *testing.T) {
t.Log("如有需要在此执行:测试之前的setup")
return func(t *testing.T) {
t.Log("如有需要在此执行:测试之后的teardown")
}
}
// 子测试的Setup与Teardown
func setupSubTest(t *testing.T) func(t *testing.T) {
t.Log("如有需要在此执行:子测试之前的setup")
return func(t *testing.T) {
t.Log("如有需要在此执行:子测试之后的teardown")
}
}
Used as follows:
func TestSplit(t *testing.T) {
type test struct { // 定义test结构体
input string
sep string
want []string
}
tests := map[string]test{ // 测试用例使用map存储
"simple": {input: "a:b:c", sep: ":", want: []string{"a", "b", "c"}},
"wrong sep": {input: "a:b:c", sep: ",", want: []string{"a:b:c"}},
"more sep": {input: "abcd", sep: "bc", want: []string{"a", "d"}},
"leading sep": {input: "沙河有沙又有河", sep: "沙", want: []string{"", "河有", "又有河"}},
}
teardownTestCase := setupTestCase(t) // 测试之前执行setup操作
defer teardownTestCase(t) // 测试之后执行testdoen操作
for name, tc := range tests {
t.Run(name, func(t *testing.T) { // 使用t.Run()执行子测试
teardownSubTest := setupSubTest(t) // 子测试之前执行setup操作
defer teardownSubTest(t) // 测试之后执行testdoen操作
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("excepted:%#v, got:%#v", tc.want, got)
}
})
}
}
Test results are as follows:
split $ go test -v
=== RUN TestSplit
=== RUN TestSplit/simple
=== RUN TestSplit/wrong_sep
=== RUN TestSplit/more_sep
=== RUN TestSplit/leading_sep
--- PASS: TestSplit (0.00s)
split_test.go:71: 如有需要在此执行:测试之前的setup
--- PASS: TestSplit/simple (0.00s)
split_test.go:79: 如有需要在此执行:子测试之前的setup
split_test.go:81: 如有需要在此执行:子测试之后的teardown
--- PASS: TestSplit/wrong_sep (0.00s)
split_test.go:79: 如有需要在此执行:子测试之前的setup
split_test.go:81: 如有需要在此执行:子测试之后的teardown
--- PASS: TestSplit/more_sep (0.00s)
split_test.go:79: 如有需要在此执行:子测试之前的setup
split_test.go:81: 如有需要在此执行:子测试之后的teardown
--- PASS: TestSplit/leading_sep (0.00s)
split_test.go:79: 如有需要在此执行:子测试之前的setup
split_test.go:81: 如有需要在此执行:子测试之后的teardown
split_test.go:73: 如有需要在此执行:测试之后的teardown
=== RUN ExampleSplit
--- PASS: ExampleSplit (0.00s)
PASS
ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s
Sample Function
Format example of a function
Was go test
treated a third function is an example of a special function, in which function name Example
prefixed. They neither argument nor return value. Standard format is as follows:
func ExampleName() {
// ...
}
Example function example
The following code is that we as Split
a sample function written in function:
func ExampleSplit() {
fmt.Println(split.Split("a:b:c", ":"))
fmt.Println(split.Split("沙河有沙又有河", "沙"))
// Output:
// [a b c]
// [ 河有 又有河]
}
The sample code for you to write code to use the following three:
The sample function can be used directly as a document, for example, a web-based godoc example can function in the corresponding packet or function associated.
Examples include long as the function
```bash split $ go test -run Example PASS ok github.com/Q1mi/studygo/code_demo/test_demo/split 0.006s ```// Output:
also cango test
perform a test run.Sample function provides sample code can be run directly, you can directly in
golang.org
thegodoc
use of the document on the serverGo Playground
running the sample code. The following figure showsstrings.ToUpper
an example of a function of the influence function in Playground.
Exercises
- Preparation of a palindrome detection function, and for the preparation of unit test and benchmarking, the results of the test to be optimized stepwise. (Palindrome: a string of positive and reverse the same, such as "Madam, I'mAdam", "less kerosene lamp" and the like.)