在开发中我们可能需要临时测试某个函数或方法的返回值是否正确,我们之前是通过在main中调用实现的
案例
package main
import "fmt"
func AddUpper(n int) int {
res := 0
for i :=1; i <=n; i++{
res += i
}
return res
}
func main(){
res := AddUpper(10) //55
if res != 55{
fmt.Printf("AddUpper错误 返回值=%v 期望值=%v\n",res,55)
}else{
fmt.Printf("AddUpper正确 返回值=%v 期望值=%v\n",res,55)
}
}
返回
AddUpper正确 返回值=55 期望值=55
传统测试的缺点
1、不方便, 需要从main中调用,如果项目正在运行就需要先停止项目
2、不利于管理,当我们测试多个函数或模块时,都需要写在main函数中,不利于清晰我们的思路
一、单元测试
go 语言自带一个测试框架testing 和go test命令来实现单元测试和性能测试
单元测试解决的问题
1、 确保每个函数是可运行的,并且运行结果正确
2、 确保写出来的代码性能是好的
3、 单元测试能及时的发现程序设计或实现的逻辑错误,是问题及早暴露
而性能测试的重点在于发现程序设计上的一些问题,让程序能够在高并发的情况下还能保持稳定
案例
我们先定义好测试的代码,如下我们要测试AddUpper函数的返回值是否正常
vi main.go
package main
func AddUpper(n int) int {
res := 0
for i :=1; i <=n; i++{
res += i
}
return res
}
func main(){
}
?编写测试文件,被测试的文件是main,所以测试文件定义为main_test.go
?vi main_test.go
package main
import "testing"
func TestAddUpper(t *testing.T) { //Test + 要测试的函数名
res := AddUpper(10) //直接调用该函数即可
if res != 55{
//t 自带的方法 Fatal失败后输出日志,然后退出
t.Fatalf("AddUpper(10) 执行错误,期望值%v 实际值=%v\n",55,res)
}
//正确后,输出日志
t.Logf("AddUpper(10) 执行正确...")
}
?测试
go test -v
返回
=== RUN TestAddUpper
main_test.go:13: AddUpper(10) 执行正确...
--- PASS: TestAddUpper (0.00s)
PASS
ok chatroom/go_pro/main 0.976s
二、单元测试细节
1、测试用例文件名必须以"_test.go"结尾,
2、测试用例函数 必须以"Test"开头, 一般来说就是"Test" + "被测试的函数名"
3、TestAddUpper(t *testing.T) 的形参类型必须是*testing.T
4、一个测试用例文件中,可以有多个测试用例函数
5、运行测试用例指令
go test //如果运行正确,无日志,错误时输出日志
go test -v //运行正确或错误都输出日志
6、当出现错误时,可以使用"t.Fatalf"来格式化输出错误,并退出程序
7、t.Logf方法可以输出相应的日志
8、 测试用例函数,并没有放在main函数中,也会被执行,这就是测试用例的方便之处
9、 PASS表示测试用例运行成功,FAIL表示测试用例运行失败
10、测试单个文件,一定要带上被测试的文件
//go test -v main_test.go main.go
11、测试单个方法 或函数
//go test -v -run TestAddUpper
关于T包含的方法
//testing包下自行查看
https://studygolang.com/pkgdoc
三、综合练习
1、 写一个Monster结构体,字段Name,Age,Skill
2、 给Monster绑定方法Store,可以将一个Monster变量,序列化后保存到文件中
3、 给Monster绑定方法ReStore,可以将一个序列化的Monster,从文件中读取,并反序列化位Monster对象,检查反序列化后,结构体名字是否正确
4、 编程测试用例文件store_test.go,编写测试用例函数TestStore和TestRestore进行测试
1、编写测试代码
vi monster.go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Monster struct{ //定义一个Monster
Name string
Age int
Skill string
}
func (this *Monster) Store() bool{ //为结构体绑定两个方法
data,err := json.Marshal(this) //序列化传入的数据为json
if err != nil{
fmt.Println("marshal err=",err)
return false
}
filePath := "d:/monster.ser"
err = ioutil.WriteFile(filePath,data,0666) //将上面序列化的数据保存为文件
if err != nil {
fmt.Println("write file error",err)
return false
}
return true
}
func (this *Monster) ReStore() bool{
filePath := "d:/monster.ser"
data,err := ioutil.ReadFile(filePath) //先读取文件内容一次性读取
if err != nil {
fmt.Println("ReadFile file error",err)
return false
}
json.Unmarshal(data,this) //将读取到的json反序列化
if err != nil{
fmt.Println("UnMarsharl file error",err)
return false
}
return true
}
2、编写单元测试
vi monster_test.go
package main
import "testing"
//测试序列化方法
func TestStore(t *testing.T){
monster := &Monster{ //声明结构体并调用
Name: "红孩儿",
Age : 10,
Skill : "吐火",
}
res := monster.Store()
if !res {
t.Fatalf("monster.Store() 错误,希望位=%v 实际为=%v",true,res)
}
t.Logf("monster.Store()测试成功")
}
//测试反序列化方法
func TestReStore(t *testing.T){
var monster Monster
res := monster.ReStore()
if !res {
t.Fatalf("monster.ReStore() 错误,希望位=%v 实际为=%v",true,res)
}
//进一步判断,有可能文件被修改之类的
if monster.Name != "红孩儿" {
t.Fatalf("monster.ReStore() 错误,希望位=%v 实际为=%v","红孩儿",res)
}
t.Logf("monster.ReStore()测试成功")
}
3、测试
go test -v monster_test.go monster.go
返回
=== RUN TestStore
monster_test.go:17: monster.Store()测试成功
--- PASS: TestStore (0.03s)
=== RUN TestReStore
monster_test.go:34: monster.ReStore()测试成功
--- PASS: TestReStore (0.00s)
PASS
ok command-line-arguments (cached)
4、单独测试某个方法
D:\go_setup\go1.17\src\go_code\go_pro\main>go test -v -run=TestStore monster_test.go monster.go
=== RUN TestStore
monster_test.go:17: monster.Store()测试成功
--- PASS: TestStore (0.00s)
PASS
ok command-line-arguments (cached)
D:\go_setup\go1.17\src\go_code\go_pro\main>go test -v -run=TestReStore monster_test.go monster.go
=== RUN TestReStore
monster_test.go:34: monster.ReStore()测试成功
--- PASS: TestReStore (0.00s)
PASS
ok command-line-arguments (cached)
想要单独测试某个方法或函数,直接通过-run=正则匹配 指定你_test.go中定义的函数即可
|