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

  提示图

image

 运行框架

image

总结

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

  

 

posted @ 2026-03-25 11:28  烟雨楼台,行云流水  阅读(3)  评论(0)    收藏  举报