go 语言之单元测试
单元测试需求
函数复杂的情况,下如何确定他的结果是正确的测试函数
传统测试方法
package main
import(
"fmt"
)
func addUpper(n int)int {
res:=0
for i:=1;i<=n;i++{
res+=i
}
return res
}
func main(){
//传统测试,在main 函数中测试
res:=addUpper(10)
if res!=55{
fmt.Printf("addupper错误 返回值=%v,期望值=%v\n",res,55)
}else{
fmt.Printf("addUpper()正确 返回值=%v,期望值=%v\n",res,55)
}
}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter16\demo01\main.go
// addupper错误 返回值=45,期望值=55
1)不方便,需要在main 函数里调用,这样就需要修改main函数代码,如果项目正在运行,就可以去停止项目
2)不利于管理。因为当需要测试多个函数或多个模块,需要写在main函数中,不利于管理
3)引出单元测试--》testing 测试框架;可以很好解决问题
单元测试介绍
Go 语言中自带一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试,testing框架和其他语言中的测试框架类似,可以基于这个框架写针对相应函数的测试用例,也可以基于该框架写相应的压力测试。通过单元测试可以解决这个问题
1)确保每个函数是可以运行,并且运行结果是正确的
2)确保写出来的代码性能是好的
3)单元测试能及时的发现程序设计或实现的逻辑错误,使问题及早暴露,便于问题的定位解决,而性能测试的重点在于发现程序设计上的一些问题,让程序能够在高并发的情况还能保持稳定
package testing
import "testing" testing 提供对 Go 包的自动化测试的支持。通过 `go test` 命令,能够自动执行如下形式的任何函数: func TestXxx(*testing.T) 其中 Xxx 可以是任何字母数字字符串(但第一个字母不能是 [a-z]),用于识别测试例程。 在这些函数中,使用 Error, Fail 或相关方法来发出失败信号。 要编写一个新的测试套件,需要创建一个名称以 _test.go 结尾的文件,该文件包含 `TestXxx` 函数,如上所述。 将该文件放在与被测试的包相同的包中。该文件将被排除在正常的程序包之外,但在运行 “go test” 命令时将被包含。 有关详细信息,请运行 “go help test” 和 “go help testflag” 了解。
示例
需要测试函数
package main
func addUpper(n int)int {
res:=0
for i:=1;i<=n;i++{
res+=i
}
return res
}
---------------------------
测试用例(文件名字有要求cal_test.go)
package main
import (
//"fmt"
"testing"//引入框架包
/*import "testing"
testing 提供对 Go 包的自动化测试的支持。通过 `go test` 命令,能够自动执行如下形式的任何函数:
func TestXxx(*testing.T)
其中 Xxx 可以是任何字母数字字符串(但第一个字母不能是 [a-z]),用于识别测试例程。*/
)
//编写测试用例测试
func TestAddUpper(t *testing.T){
res :=addUpper(10)
if res!=55{
// fmt.Printf("addupper错误 返回值=%v,期望值=%v\n",res,55)
t.Fatalf("addupper错误 返回值=%v,期望值=%v\n",res,55)
}
t.Logf("addupper执行正确")
}
PS D:\golang\goproject\src\src01\go_code\src\chapter16\demo02> go test -v
=== RUN TestAddUpper
cal_test.go:20: addupper执行正确
--- PASS: TestAddUpper (0.00s)
PASS
ok src01/go_code/src/chapter16/demo02 0.464s
提示图

运行框架

总结
1)测试用例文件名必须以_test.go结尾,例如cal_test.go,cal_不是固定得
2)测试用例函数必须以Test开头,一般来说就是Test+被测试的函数名,例如TestAddUpper
3)TestAddUpper(t *testing.T)的形参类型必须是*testing.T
4)一个测试用例文件中,可以有多个测试用例函数,比如TestAddUpper、TestSub
5)运行测试用例指令
(1)cmd >go test [如果运行正确,无日志,错误时,会输出日志]
(2)cmd>go test -v [运行正确或错误,都输出日志]
6)当出现错误时,可以使用t.Fatalf 来格式化输出错误信息,并退出程序
7)t.Logf方法可以输出相应的日志
8)测试用例函数,并没有放在main函数中,也执行了,这就是测试用例的方便之处。
9)PASS表示测试用例运行成功,FAIL表示测试用例运行失败
10)测试单个文件,一定带上被测试的源文件
PS D:\golang\goproject\src\src01\go_code\src\chapter16\demo02> go test -v cal_test.go cal.go
11)测试单个函数
PS D:\golang\goproject\src\src01\go_code\src\chapter16\demo02> go test -v -run TestAddUpper
=== RUN TestAddUpper
cal_test.go:16: addupper执行正确
--- PASS: TestAddUpper (0.00s)
PASS
ok src01/go_code/src/chapter16/demo02 0.354s
测试实例
代码
package main
import (
"bufio"
"encoding/json"
"fmt"
//"io/ioutil"
//"testing/iotest"
//"io"
"os"
)
type Monster struct{
Nama string
Age int
Skill string
}
func (t *Monster)Store() bool{
data,err:=json.Marshal(t)
if err != nil{
fmt.Printf("错误err=%v\n",err)
return false
}
fild := "d:/Monster.ser"
err=os.WriteFile(fild,data,0666)
if err !=nil{
fmt.Printf("保存出错err=%v",err)
return false
}
return true
}
func (t *Monster)ReStore() bool{
//读取序列化后字符串
fild := "d:/Monster.ser"
data,err:=os.ReadFile(fild)
if err !=nil{
fmt.Printf("读取文件错,误err=%v\n",err)
return false
}
err=json.Unmarshal([]byte(data),t)
if err !=nil{
fmt.Printf("Unmarshal err=%v\n",err)
}
//fmt.Println(t)
return true
}
func Writer(){
file,err:= os.OpenFile("d:/a.txt",os.O_WRONLY|os.O_CREATE,0666)
if err !=nil{
fmt.Printf("错误err=%v\n",err)
return
}
defer file.Close()
m := Monster{
Nama: "孙悟空",
Age: 1500,
Skill: "七十二变",
}
data,err:=json.Marshal(&m)
if err !=nil {
fmt.Printf("序列化失败,err=%V\n",err)
return
}
Writer:=bufio.NewWriter(file)
Writer.WriteString(string(data))
Writer.Flush()
}
func Read(){
//file,err:= os.OpenFile("d:/a.txt",os.O_RDONLY,0666)
file:="d:/a.txt"
//defer file.Close()
// if err !=nil{
// fmt.Printf("文件打开失败err=\n",err)
// return
// }
// read:=bufio.NewReader(file)
t,err :=os.ReadFile(file)
if err!=nil{
return
}
m := Monster{}
//str,err:=read.ReadString('}')
// if err ==io.EOF{
// return
// }
err=json.Unmarshal([]byte(t),&m)
if err !=nil{
fmt.Printf("Unmarshal err=%v\n",err)
}
fmt.Println(m)
}
以上代码测试用例
package main
import (
"testing"
//"fmt"
)
func TestWriter(t *testing.T) {
Writer()
}
func TestRead(t *testing.T) {
Read()
}
func TestStore(t *testing.T){
//创建
monster :=Monster{
Nama:"牛魔王",
Age: 5000,
Skill: "牛魔拳",
}
res:=monster.Store()
if !res {
t.Fatalf("序列化失败")
}
t.Logf("测试成功")
}
func TestReStore(t *testing.T){
//创建
monster :=Monster{}
res:=monster.ReStore()
if !res {
t.Fatalf("monster.ReStore()错误,希望是=%v,实际=%v",true,res)
}
if monster.Nama !="牛魔王"{
t.Fatalf("monster.ReStore()错误,希望=%v。实际=%v","牛魔王",monster.Nama)
}
t.Logf("测试成功")
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src\chapter16\demo03> go test -v -run TestStore
// === RUN TestStore
// json_test.go:25: 测试成功
// --- PASS: TestStore (0.00s)
// PASS
// ok src01/go_code/src/chapter16/demo03 0.464s
// PS D:\golang\goproject\src\src01\go_code\src\chapter16\demo03> go test -v
// === RUN TestWriter
// --- PASS: TestWriter (0.00s)
// === RUN TestRead
// {孙悟空 1500 七十二变}
// --- PASS: TestRead (0.00s)
// === RUN TestStore
// json_test.go:25: 测试成功
// --- PASS: TestStore (0.00s)
// === RUN TestReStore
// json_test.go:37: 测试成功
// --- PASS: TestReStore (0.00s)
// PASS
// ok src01/go_code/src/chapter16/demo03 0.410s

浙公网安备 33010602011771号