当前位置:网站首页>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 .
边栏推荐
- Examination questions for the assignment of selected readings of British and American Literature in the course examination of Fujian Normal University in February 2022
- Svn full backup svnadmin hotcopy
- [RT thread] NXP rt10xx device driver framework -- pin construction and use
- [combinatorics] recursive equation (special solution form | special solution solving method | special solution example)
- The most complete postman interface test tutorial in the whole network, API interface test
- Bcvp developer community 2022 exclusive peripheral first bullet
- 简单配置PostFix服务器
- SWM32系列教程4-端口映射及串口应用
- [combinatorics] recursive equation (characteristic equation and characteristic root | example of characteristic equation | root formula of monadic quadratic equation)
- [combinatorics] recursive equation (general solution structure of recursive equation with multiple roots | linear independent solution | general solution with multiple roots | solution example of recu
猜你喜欢

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

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

What is your income level in the country?

One brush 147-force deduction hot question-4 find the median of two positive arrays (H)

Kubernetes resource object introduction and common commands (V) - (NFS & PV & PVC)

Prepare for the golden three silver four, 100+ software test interview questions (function / interface / Automation) interview questions. win victory the moment one raises one 's standard

Kotlin learning quick start (7) -- wonderful use of expansion
![[UE4] brush Arctic pack high quality Arctic terrain pack](/img/e7/bc86bd8450b0b2bdec8980a2aa1a10.jpg)
[UE4] brush Arctic pack high quality Arctic terrain pack
![[try to hack] active detection and concealment technology](/img/43/d48f851268fec566ce0cc83bd9557e.png)
[try to hack] active detection and concealment technology

Collection of the most beautiful graduation photos in the graduation season, collection of excellent graduation photos
随机推荐
Analysis of variance summary
Thread pool: the most common and error prone component of business code
[JDBC] API parsing
Vs code plug-in korofileheader
Svn full backup svnadmin hotcopy
大变局!全国房价,跌破万元大关
Life is still confused? Maybe these subscription numbers have the answers you need!
Design e-commerce spike
Dagong 21 autumn "power plant electrical part" online operation 1 [standard answer] power plant electrical part
【JokerのZYNQ7020】DDS_ Compiler。
手把手带你入门 API 开发
POM in idea XML graying solution
[2. Basics of Delphi grammar] 1 Identifiers and reserved words
新库上线 | CnOpenData中国观鸟记录数据
How to delete a specific line from a text file using the SED command?
Examination questions for the assignment of selected readings of British and American Literature in the course examination of Fujian Normal University in February 2022
The most complete postman interface test tutorial in the whole network, API interface test
New library online | cnopendata China bird watching record data
C language modifies files by line
27. 输入3个整数,按从大到小的次序输出。要求用指针方法实现。