Go-知识测试-示例测试
Go-知识测试-示例测试
- 1. 定义
- 2. 例子
- 3. 数据结构
- 4. 编译过程
- 5. 执行过程
建议先看:https://blog.csdn.net/a18792721831/article/details/140062769
Go-知识测试-工作机制
1. 定义
示例测试要保证测试文件以_test.go结尾。
测试方法必须以ExampleXxx开头。
测试文件可以与源码处于同一目录,也可以处于单独的目录。
检测单行输出格式为 // Output:
检测多行输出格式为 // Output: \n \n \n,每个期望字符串占一行
检测无序输出格式为 // Unordered output: \n \n \n ,每个期望字符串占一行
测试字符串会自动忽略字符串前后的空白字符
如果测试函数中没有Output表示,则测试函数不会被执行
2. 例子
在字符串输出中,可能是一行,可能是多行,也有可能是乱序
函数如下:
func Hello() { fmt.Println("Hello") } func HelloTwo() { fmt.Println("Hello") fmt.Println("hi") } func HelloMore() { m := make(map[string]string) m["hello"] = "Hello" m["hi"] = "hi" m["你好"] = "你好" for _, v := range m { fmt.Println(v) } }
接着使用示例测试
func ExampleHello() { Hello() // Output: Hello } func ExampleHelloTwo() { HelloTwo() // Output: // Hello // hi } func ExampleHelloMore() { HelloMore() // Unordered output: // Hello // hi // 你好 }
使用go test -v 执行示例测试,-v 表示控制台输出结果
3. 数据结构
每个测试经过编译后都有一个数据结构来承载,对于示例测试就是InternalExample:
type InternalExample struct { Name string // 测试名称 F func() // 测试函数 Output string // 期望字符串 Unordered bool // 输出是否无序 }
比如如下case:
func ExampleHelloMore() { HelloMore() // Unordered output: // Hello // hi // 你好 }
编译后,数据结构成员
InternalExample.Name = "ExampleHelloMore" InternalExample.F = ExampleHelloMore() InternalExample.Output = "hello\nhi\n你好\n" InternalExample.Unordered = true
4. 编译过程
在文章: Go-知识测试-工作机制
Go-知识测试-工作机制
中,我们知道编译的时候,会调用src/cmd/go/internal/load/test.go:528
在 load 里面会对四种测试进行分别处理:单元测试,性能测试,Main测试和示例测试
在对测试文件进行处理时,会查看注释中是否包含 output
并且封装好元数据
封装好元数据后,会使用元数据渲染模板,生成Main入口,并同时渲染InternalExample切片
5. 执行过程
在执行的时候,会执行testing.M.Run,在Run里面会执行runExamples
func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) { ok = true var eg InternalExample // 对每个实例测试进行执行 for _, eg = range examples { // 是否匹配 matched, err := matchString(*match, eg.Name) if err != nil { fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err) os.Exit(1) } if !matched { continue } ran = true // 执行 if !runExample(eg) { ok = false } } return ran, ok }
func runExample(eg InternalExample) (ok bool) { // 附加输出 if *chatty { fmt.Printf("=== RUN %s\n", eg.Name) } // 获取标准输出 stdout := os.Stdout // 新建管道,将标准输出拷贝一份 r, w, err := os.Pipe() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } os.Stdout = w // 创建一个管道,用于接收标准输出返回的字符串 outC := make(chan string) // 在一个单独的 goroutine 中处理拷贝的输出 go func() { var buf strings.Builder _, err := io.Copy(&buf, r) r.Close() if err != nil { fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err) os.Exit(1) } outC