当前位置:网站首页>Golang unit test, mock test and benchmark test
Golang unit test, mock test and benchmark test
2022-07-03 17:18:00 【Small dish chicken dish】
Notes from the ByteDance youth training camp
Golang Have a set of unit testing and performance testing system , You can quickly test a piece of requirement code with very little additional code .
One 、 unit testing

Unit testing mainly includes : Input 、 Test unit 、 Output 、 Expectations and proofreading with expectations .
Test units include functions or modules combined with some functions . We check the output with the expected value , To verify the correctness of the code .
Pass the unit test , On the one hand, it can guarantee the quality , For example, when the coverage is sufficient , If you add new code to the old code , Unit tests can verify whether the new code destroys the functional correctness .
On the other hand , It also improves efficiency , For example, in the code bug, By writing unit tests , We can locate or fix the problem in a short time .
1.1、golang The rules
The rules 1: All test documents are in _test.go ending .
_test.go The program will not be ordinary Go Compiler compilation , So when applications are deployed to the production environment, they will not be deployed ;
Only gotest Will compile all programs : General procedures and test procedures .
The rules 2: The test file must be imported testing package , And the function must be written as func TestXxx(*testing.T) form .
for example , Some function Add The test function of is TestAdd, As shown below :
//main.go
func Add(a, b int) int {
return a + b
}
//main_test.go
func TestAdd(t *testing.T) {
trueOutput := Add(1, 2)
expectOutput := 3
if trueOutput != expectOutput {
t.Errorf("Expected %v do not match actual %v", expectOutput, trueOutput)
}
}
The rules 3: The initialization logic of the test is put into TestMain in .
This is a good usage ,TestMain The specific information of the function is as follows :
func TestMain(m *testing.M){
// Before testing : Data loading 、 Configuration initialization and other pre work
//...
code := m.Run()
// After testing : Release resources and other finishing work
//...
os.Exit(code)
}
for example :
func TestMain(m *testing.M) {
// Before testing
fmt.Println(" Here we go !")
run := m.Run()
// After testing
fmt.Println(" It's over !")
os.Exit(run)
}
func TestAdd(t *testing.T) {
trueOutput := Add(1, 2)
expectOutput := 3
if trueOutput != expectOutput {
t.Errorf("Expected %v do not match actual %v", expectOutput, trueOutput)
}
}
// test result
// Here we go !
//=== RUN TestAdd
//--- PASS: TestAdd (0.00s)
//PASS
//
// It's over !
1.2、 give an example & Third party test package
In this example , We expect HelloTom The function returns “Tom”, If not “Tom” It means that the test failed .
Obviously , This test failed .
func HelloTom() string {
return "Jerry"
}
func TestHelloTom(t *testing.T) {
output := HelloTome()
expectOutput := "Tom"
if output != expectOutput {
t.Errorf("Expected %s do not match actual %s", expectOutput, output)
}
}
// test result
//=== RUN TestHelloTom
//main_test.go:28: Expected Tom do not match actual Jerry
//--- FAIL: TestHelloTom (0.00s)
In the unit test function , It is often necessary to write judgment logic , We can use some open source test packages to help simplify the code .
For example, using Testift. Use go get install :
go get github.com/stretchr/testify
Use the above example Testify after , The code is as follows :
func TestHelloTom(t *testing.T) {
output := HelloTom()
assert.Equal(t, "Tom", output)
}
1.3、 coverage
problem :
- How to measure whether the code has passed enough tests ?
- How to evaluate the test level of the project ?
- How to evaluate whether the project has reached a high level of testing ?
We need to evaluate unit tests , So we need to introduce unit test coverage .
Coverage reflects the coverage of test cases to a certain extent , The more complete, the more guaranteed the correctness of the code .
Example :
func JudgePassLine(score int16) bool {
if score >= 60 {
return true
}
return false
}
func TestJudgePassLine(t *testing.T) {
isPass := JudgePassLine(70)
expectOutput := true
if expectOutput != isPass {
t.Errorf("Expected %v do not match actual %v", expectOutput, isPass)
}
}
Use command :
go test judgment_test.go judgment.go --cover
result :
=== RUN TestJudgePassLine
--- PASS: TestJudgePassLine (0.00s)
PASS
coverage: 40.0% of statements in ./...
If you use Goland Words , The scope of the test code will be displayed . Obviously ,JudgePassLine The first two lines of the function ( In the example, the second 2、3 That's ok ) Has been verified , and return false Not verified .
We can write another branch unit test , To improve coverage .
func TestJudgePassLine(t *testing.T) {
isPass := JudgePassLine(70)
expectOutput := true
if expectOutput != isPass {
t.Errorf("Expected %v do not match actual %v", expectOutput, isPass)
}
}
func TestJudgePassLineFail(t *testing.T) {
isPass := JudgePassLine(50)
expectOutput := false
if expectOutput != isPass {
t.Errorf("Expected %v do not match actual %v", expectOutput, isPass)
}
}
// result
//=== RUN TestJudgePassLine
//--- PASS: TestJudgePassLine (0.00s)
//=== RUN TestJudgePassLineFail
//--- PASS: TestJudgePassLineFail (0.00s)
//PASS
//
//coverage: 60.0% of statements in ./...
It can be seen from the results , At present, the coverage rate has reached 60% 了 ( There are other functions that do not write unit tests ).
Of course , In the actual project , To achieve 100% Coverage is an unreachable goal , Generally speaking , Coverage is in 50%~60% It can be considered that there is no problem in some mainstream situations , But there may be some abnormal branches that are not covered , For some, such as ” Withdrawal “ And other capital operations , The coverage rate will be higher , Generally, coverage is required 80% above .
In order to improve coverage , There are some good practices :
- The test branches are independent of each other 、 Full coverage .
- The granularity of the test unit is small enough , Therefore, the function is required to have a single responsibility .
Two 、Mock test
2.1、 Dependencies in the project

In some complex projects , Will rely on some databases 、 File or cache , These are a strong dependency of the project .
The main objectives of unit testing are 2 individual :
- idempotent . Idempotent means that the result of running a test repeatedly is consistent with that before .
- Stable . Unit tests can be isolated from each other , Functions in unit tests can run independently at any time and anywhere .
If external dependencies such as database are called directly in unit test , That test is unstable , for example :
func ReadFirstLine() string {
open, err := os.Open("log")
defer open.Close()
if err != nil {
return ""
}
scanner := bufio.NewScanner(open)
for scanner.Scan() {
return scanner.Text()
}
return ""
}
func ProcessFirstLine() string {
line := ReadFirstLine()
destLine := strings.ReplaceAll(line, "11", "00")
return destLine
}
//Test
func TestProcessFirstLine(t *testing.T) {
firstLine := ProcessFirstLine()
expectOutput := "line00"
if firstLine != expectOutput {
t.Errorf("Expected %s do not match actual %s", expectOutput, firstLine)
}
}
You can see from this example that , The test depends on external files , If the external file is deleted or tampered , Then this test cannot be run .
So we need to introduce mock Mechanism .
2.2、Mock
Common open source Mock package monkey:https://github.com/bouk/monkey
The package provides fast Mock function :
- For a function
- Pile for a method
Piling can be understood as using a function A To replace a function B,B It's the original function ,A Is the piling function .
Example :
Modify the above read file unit test code , Yes ReadFirstLine Pile driving test , Make the test no longer depend on local files .
func TestProcessFirstLine(t *testing.T) {
//mock Pile driving
monkey.Patch(ReadFirstLine, func() string {
return "line00"
})
defer monkey.Unpatch(ReadFirstLine)
//
firstLine := ProcessFirstLine()
expectOutput := "line00"
if firstLine != expectOutput {
t.Errorf("Expected %s do not match actual %s", expectOutput, firstLine)
}
}
mock Implement... At run time , be based on go Of unsafe package , Replace the address of the function in memory with the address of the runtime function .
3、 ... and 、 The benchmark
go Provides a benchmarking framework , Benchmarking refers to testing the performance of a program when it runs .
In benchmarking , Function will be called N Time (N Is a very large number , Such as N = 1000000), And show N And the average time of function execution , Unit is ns( nanosecond ,ns/op).
- Using benchmarks can optimize code , Of course , This requires analysis of the current code .
Example :
Load balancing example , Randomly select the execution server
var ServerIndex [10]int
func InitServerIndex() {
for i := 0; i < 10; i++ {
ServerIndex[1] = i + 100
}
}
func Select() int {
return ServerIndex[rand.Intn(10)]
}
// test
// Serial benchmark
func BenchmarkSelect(b *testing.B) {
InitServerIndex()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Select()
}
}
// Parallel benchmarks
func BenchmarkSelectParallel(b *testing.B) {
InitServerIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Select()
}
})
}
test result :
BenchmarkSelect-16 180309266(N) 6.596 ns/op( The average time of function execution )
BenchmarkSelectParallel-16 29328594 42.33 ns/op
You can see that in the parallel state , Low performance , because Select Take advantage of rand function , and rand Function to ensure randomness and concurrency safety , Hold a global lock , This reduces concurrency .
In order to improve the performance of this function , It can be used fastrand.
func BenchmarkFastSelectParallel(b *testing.B) {
InitServerIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
FastSelect()
}
})
}
result :
BenchmarkFastSelectParallel-16 1000000000 0.5274 ns/op
Four 、 summary
- Golang Provides simple and powerful testing tools , And according to Golang The rules of , It also enables developers to know at a glance which function a unit test corresponds to .
- Using a third-party unit test kit can simplify our code .
- When external dependencies need to be used , We can use Mock Test to simulate external dependencies , Avoid unnecessary mistakes .
- Benchmark can get the performance of a program , It is convenient for developers to optimize , For example, given above “ Randomly select the execution server ” Example .
边栏推荐
- Svn full backup svnadmin hotcopy
- POM in idea XML graying solution
- LeetCode13.罗马数字转整数(三种解法)
- The difference between get and post
- Luogu: p1155 [noip2008 improvement group] double stack sorting (bipartite graph, simulation)
- 29: Chapter 3: develop Passport Service: 12: develop [obtain user account information, interface]; (use VO class to package the found data to meet the requirements of the interface for the returned da
- 鸿蒙第四次培训
- Open vsftpd port under iptables firewall
- kubernetes资源对象介绍及常用命令(五)-(NFS&PV&PVC)
- Redis:关于列表List类型数据的操作命令
猜你喜欢

跨境电商:外贸企业做海外社媒营销的优势

问题随记 —— 在 edge 上看视频会绿屏

ANOVA example
![[error reporting] omp: error 15: initializing libiomp5md dll, but found libiomp5md. dll already initialized.](/img/a0/4fc0e0741aad2885873e60f2af3387.jpg)
[error reporting] omp: error 15: initializing libiomp5md dll, but found libiomp5md. dll already initialized.

Golang单元测试、Mock测试以及基准测试

New features of C 10

kubernetes资源对象介绍及常用命令(五)-(NFS&PV&PVC)

Is AI too slow to design pictures and draw illustrations? 3 sets of practical brushes to save you

Free data | new library online | cnopendata complete data of China's insurance intermediary outlets

【RT-Thread】nxp rt10xx 设备驱动框架之--Pin搭建和使用
随机推荐
[2. Basics of Delphi grammar] 1 Identifiers and reserved words
One brush 145 force deduction hot question-2 sum of two numbers (m)
[error reporting] omp: error 15: initializing libiomp5md dll, but found libiomp5md. dll already initialized.
Résolution de l'instance d'assemblage - - affichage à l'écran en mode réel
ANOVA example
C语言字符串反转
[combinatorics] recursive equation (special solution example 1 Hannover tower complete solution process | special solution example 2 special solution processing when the characteristic root is 1)
【RT-Thread】nxp rt10xx 设备驱动框架之--Audio搭建和使用
How to judge the region of an IP through C?
Assembly instance analysis -- screen display in real mode
Rsync远程同步
Define a structure fraction to represent a fraction, which is used to represent fractions such as 2/3 and 5/6
One brush 142 monotone stack next larger element II (m)
在iptables防火墙下开启vsftpd的端口
Squid 服务启动脚本
Leetcode: lucky number in matrix
绝对定位时元素水平垂直居中
HP 阵列卡排障一例
Dagong 21 autumn "power plant electrical part" online operation 1 [standard answer] power plant electrical part
SSH连接远程主机等待时间过长的解决方法