当前位置:网站首页>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 .
边栏推荐
- [combinatorics] recursive equation (special solution form | special solution solving method | special solution example)
- How do large consumer enterprises make digital transformation?
- 数仓任务里面 跑SQL任务的时候用的数据库账号是在哪里配置的
- 企业级自定义表单引擎解决方案(十一)--表单规则引擎1
- 新库上线 | CnOpenData中国保险机构网点全集数据
- An example of HP array card troubleshooting
- [RT thread] NXP rt10xx device driver framework -- RTC construction and use
- 聊聊接口优化的几个方法
- University of Electronic Science and technology, accounting computerization, spring 20 final exam [standard answer]
- One brush 144 force deduction hot question-1 sum of two numbers (E)
猜你喜欢
[JDBC] API parsing
Life is still confused? Maybe these subscription numbers have the answers you need!
静态程序分析(一)—— 大纲思维导图与内容介绍
1164 Good in C
Golang单元测试、Mock测试以及基准测试
Applet setting multi account debugging
【RT-Thread】nxp rt10xx 设备驱动框架之--Audio搭建和使用
New features of C 10
POM in idea XML graying solution
One brush 145 force deduction hot question-2 sum of two numbers (m)
随机推荐
Résolution de l'instance d'assemblage - - affichage à l'écran en mode réel
网络硬盘NFS的安装与配置
Luogu: p1155 [noip2008 improvement group] double stack sorting (bipartite graph, simulation)
RedHat 6.2 配置 Zabbix
ANOVA example
Electronic technology 20th autumn "Introduction to machine manufacturing" online assignment 3 [standard answer]
Applet setting multi account debugging
One brush 142 monotone stack next larger element II (m)
Leetcode: lucky number in matrix
【Try to Hack】主动侦查隐藏技术
1164 Good in C
Dagong 21 autumn "power plant electrical part" online operation 1 [standard answer] power plant electrical part
Test your trained model
HP 阵列卡排障一例
Collection of the most beautiful graduation photos in the graduation season, collection of excellent graduation photos
[UE4] brush Arctic pack high quality Arctic terrain pack
问题随记 —— 在 edge 上看视频会绿屏
Open vsftpd port under iptables firewall
vs2013已阻止安装程序,需安装IE10
The difference between get and post