单元测试作用:确认一个函数或者一个package引入后的结果是否正确。
传统方法:测试输出的结果是否和预期结果一致,
有些东西要放在生产环境做,才能有效,测试环境下没有这种环境;
不利于管理,所以需要测试框架来解决上述问题。
Golang中带有一个轻量级的测试框架testing , go test测试命令来实现单元测试和性能测试(执行代码花费时间)。
通过单元测试解决下面问题:
- 确保每个函数是可运行,并且结果输出时正确的。
- 确保写出来的代码性能是好的
- 单元测试能及时发现程序设计和实现的逻辑错误,使用问题及早暴露,便于问题的定位解决。
- 性能测试的重点在于程序设计上的一些问题,让程序能够在高并发的情况下还能保持稳定。
单元测试的使用
- 测试单独建立一个文件夹,用来和main()隔离,测试文件的运行不需要main()入口。
- .go测试文件中的函数,提取到_test.go文件中,_test.go需要import Testing包。
示例:
package tst
import "testing"
func Test<dest>(t *testing.T) {
//引入测试函数1
//引入测试函数2
}
案例模拟:创建一个tst包,然后在里面写入两个文件,Accumu.go和Accumu_test.go,两个文件写法如下
Accumu.go
//>>> Accumu.go <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
package tst
func Accumu(n int) int { //就是一个累加器,没啥说得,没有main()
res := 0
for i := 0 ; i <= n ; i++ {
res += i
}
return res
}
Accumu_test.go
//>>> Accumu_test.go <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//测试单个文件:切换到此目录下,go test -v会默认测试所有函数,如果只想测试其中一个,需要命令 go test -v Accumu_test.go Accumu.go
//测试单个方法:切换到此目录下,需要命令 go test -v -test.run Accumu
package tst
import (
"testing" //需要导入testing包
)
func TestAccumu(t *testing.T) { //在Goland中,默认test文件都会直接出此类格式
res := Accumu(10) //测试结果与res所传函数有关,与函数名无关
if res != 55 {
t.Fatalf("应输入值为%v,实际输出为%v",55,res) //遇到错误即终止,并会反馈结果为FAIL
}
t.Logf("程序测试正确!") //如果测试无异常则打印PASS,后面日志为t.logf()中的字符串内容
} //关于测试结果,Goland中测试文件都会有一个红色箭头,因此无需黑屏终端go test命令来使用
测试结果如下:
/*
e:\Golear\src\tst>go test -v
=== RUN TestAccumu
--- PASS: TestAccumu (0.00s)
cal_test.go:12: 程序测试正确!
PASS
ok _/e_/Golear/src/tst 0.536s
e:\Golear\src\tst>go test -v -test.run Accumu
=== RUN TestAccumu
--- PASS: TestAccumu (0.00s)
cal_test.go:12: 程序测试正确!
PASS
ok _/e_/Golear/src/tst 0.607s
*/
序列化和反序列化+文件使用+单元测试 结合实战应用:
需求:创建一个结构体:Heros
字段:Name string, Age int, Hobby string
方法:Store()将结构体变量序列化后保存到文件kunkun.txt中
RevStore()将结构体变量从文件kunkun.txt汇总读取并反序列化
单元测试:测试上述两个方法是否正常。
核心代码段:(假设作为生产,不可以轻易测试)
package main
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type KunFamily struct {
Name string `json:"name"`
Age int `json:"age"`
Hobby string `json:"hobby"`
}
func (k *KunFamily) Store() bool { //为了确保测试,故返回布尔值
slice, err := json.Marshal(k)
if err != nil {
fmt.Println("序列化失败,失败原因为: ",err)
return false
}
file, err := os.OpenFile("D:/kunkun.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("请检查错误为:", err)
return false
}
defer file.Close()
writer := bufio.NewWriter(file)
_, _ = writer.WriteString(string(slice))
_ = writer.Flush()
return true
}
func (k *KunFamily) RevStore() bool { //为了确保测试,故返回布尔值
//读取文件
file := "D:/kunkun.txt"
content, err := ioutil.ReadFile(file)
if err != nil {
fmt.Println("读取错误,错误为:", err)
return false
}
//反序列化
err1 := json.Unmarshal([]byte(content), k) //err := json.Unmarshal([]byte(string), &<struct结构体变量>)
if err1 != nil {
fmt.Println("反序列化出现异常,异常报错为:",err1)
return false
}
return true
}
func main() {
var caixukun1 = &KunFamily{"蔡徐坤1",20,"鸡你太美"}
caixukun1.Store()
caixukun1.RevStore()
}
被测试文件写法:(从生产代码段摘出,x.go)
package tst
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type KunFamily struct {
Name string `json:"name"`
Age int `json:"age"`
Hobby string `json:"hobby"`
}
func (k *KunFamily) Store() bool {
slice, err := json.Marshal(k)
if err != nil {
fmt.Println("序列化失败,失败原因为: ",err)
return false
}
file, err := os.OpenFile("D:/kunkun.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("请检查错误为:", err)
return false
}
defer file.Close()
writer := bufio.NewWriter(file)
_, _ = writer.WriteString(string(slice))
_ = writer.Flush()
return true
}
func (k *KunFamily) RevStore() bool {
file := "D:/kunkun.txt"
content, err := ioutil.ReadFile(file)
if err != nil {
fmt.Println("读取错误,错误为:", err)
return false
}
err1 := json.Unmarshal([]byte(content), k) //err := json.Unmarshal([]byte(string), &<struct结构体变量>)
if err1 != nil {
fmt.Println("反序列化出现异常,异常报错为:",err1)
return false
}
return true
}
测试文件写法:(x_test.go)
package tst
import (
"testing"
)
func TestKunFamily_Store(t *testing.T) {
var caixukun = &KunFamily{"蔡徐坤1",20,"鸡你太美"}
res := caixukun.Store()
if res != true {
t.Fatalf("测试失败")
}
t.Logf("程序测试正确!")
}
func TestKunFamily_RevStore(t *testing.T) {
var caixukun = &KunFamily{"蔡徐坤1",20,"鸡你太美"}
res := caixukun.RevStore()
if res != true {
t.Fatalf("测试失败")
}
t.Logf("程序测试正确!")
}