当前位置:网站首页>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 .
边栏推荐
- 【JokerのZYNQ7020】DDS_ Compiler。
- Assembly instance analysis -- screen display in real mode
- 网络硬盘NFS的安装与配置
- C语言按行修改文件
- vs code 插件 koroFileHeader
- 汇编实例解析--实模式下屏幕显示
- 【RT-Thread】nxp rt10xx 设备驱动框架之--Pin搭建和使用
- Great changes! National housing prices fell below the 10000 yuan mark
- Take you to API development by hand
- A day's work list of an ordinary programmer
猜你喜欢

【RT-Thread】nxp rt10xx 设备驱动框架之--Pin搭建和使用

Design e-commerce spike

1164 Good in C

Collection of the most beautiful graduation photos in the graduation season, collection of excellent graduation photos

Thread pool: the most common and error prone component of business code

POM in idea XML graying solution

How to train mask r-cnn model with your own data
![[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.

Kotlin learning quick start (7) -- wonderful use of expansion

Life is still confused? Maybe these subscription numbers have the answers you need!
随机推荐
RDS数据库的监测页面在哪看?
Analysis of variance summary
Financial management (Higher Vocational College) financial management online Assignment 1 in autumn 20
RedHat 6.2 配置 Zabbix
鸿蒙第三次培训
建立自己的网站(23)
Fast Ethernet and Gigabit Ethernet: what's the difference?
匯編實例解析--實模式下屏幕顯示
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
问题随记 —— 在 edge 上看视频会绿屏
Comparison of kotlin collaboration + retro build network request schemes
C language string inversion
[combinatorics] recursive equation (constant coefficient linear homogeneous recursive equation | constant coefficient, linear, homogeneous concept description | constant coefficient linear homogeneous
1164 Good in C
大变局!全国房价,跌破万元大关
设计电商秒杀
Life is still confused? Maybe these subscription numbers have the answers you need!
Vs code plug-in korofileheader
Examination questions for the assignment of selected readings of British and American Literature in the course examination of Fujian Normal University in February 2022
Redis: operation commands for list type data