This is a creation in Article, where the information may have evolved or changed.
The important point of the development program is the test, how we guarantee the quality of the code, how to ensure that each function is operational, the result is correct, and how to ensure that the written code performance is good, we know that the focus of unit testing is to find the design or implementation of logic errors, so that the problem early exposure, Easy to solve the problem, and the focus of performance testing is to find some programming problems, so that the online program can be high concurrency in the case can remain stable. This section will take this series of questions to explain how to implement unit and performance testing in the Go language.
The go language comes with a lightweight test framework testing
and comes with go test
commands to implement unit testing and performance testing, testing
and frameworks are similar to test frameworks in other languages, where you can write test cases for corresponding functions based on the framework, or you can write the appropriate stress test cases based on the framework. Then let's hit to see how to write.
How to write test cases
Since the go test
command can only execute all the files in one of the corresponding directories, we will create a new project directory so that gotest
all of our code and test code are in this directory.
Next we create two files under this directory: Gotest.go and Gotest_test.go
Gotest.go: In this file we create a package with a function that divides the operation:
Package Gotestimport ( "errors") Func division (A, B float64) (float64, error) { if b = = 0 { return 0, errors. New ("Divisor cannot be 0") } return a/b, nil}
Gotest_test.go: This is our unit test file, but keep in mind the following principles:
- The file name must be
_test.go
at the end so that it executes go test
to the appropriate code at execution time
- You have to import
testing
this bag.
- All test case functions must be at the
Test
beginning
- The tests are executed in the order in which they were written in the source code.
- The parameter of the test function
TestXxx()
is testing.T
that we can use that type to log an error or test state
- Test format:
func TestXxx (t *testing.T)
, Xxx
part can be any combination of alphanumeric, but the first letter can not be lowercase letters [a-z], such as the Testintdiv
wrong function name.
- The function in the call,,,
testing.T
Error
Errorf
FailNow
Fatal
FatalIf
method, means that the test does not pass, and the calling Log
method is used to record the test information.
Here is the code for our test case:
Package Gotestimport ( "testing") Func test_division_1 (t *testing. T) { If I, E: = Division (6, 2); I! = 3 | | E! = NIL {//try A unit test on function t.error ("Division function test Failed")//if not as expected Error } else { t.Log ("first Test Passed")//record some information you expect to record }}func test_division_2 (t *testing. T) { t.error ("Just Don't Pass")}
When we execute under the project directory go test
, the following information is displayed:
---fail:test_division_2 (0.00 seconds) Gotest_test.go:16: is not through Failexit status 1FAIL gotest 0.013s
From this the result shows that the test did not pass, because in the second Test function we wrote dead The test does not pass the code t.Error
, then our first function to execute the situation? By default, execution go test
does not show the information passed by the test, and we need to bring the parameters so that the go test -v
following information is displayed:
= = = Run test_division_1---pass:test_division_1 (0.00 seconds) Gotest_test.go:11: The first Test passed the = = = Run Test_division_2 ---fail:test_division_2 (0.00 seconds) Gotest_test.go:16: is not through Failexit status 1FAIL gotest 0.012s
The above output shows the process of the test in detail, we see the test function 1 Test_Division_1
test pass, and the test function 2 Test_Division_2
test failed, and finally concluded that the test does not pass. Next we change the test function 2 to the following code:
Func test_division_2 (t *testing. T) { If _, E: = Division (6, 0), E = = Nil {//try A unit test on function t.error ("Division do not work as Expecte D. ") If not as expected then error } else { t.Log ("one Test passed.", e)//record some information you wish to record }}
Then we execute go test -v
, the following information is displayed, the test passed:
= = = Run test_division_1---pass:test_division_1 (0.00 seconds) Gotest_test.go:11: The first Test passed the = = = Run test_division_2- --Pass:test_division_2 (0.00 seconds) Gotest_test.go:20:one Test passed. Divisor cannot be 0PASSok gotest 0.013s
How to write a stress test
Stress tests are used to detect the performance of functions (methods), similar to the method of writing unit functional tests, which are not mentioned here, but note the following points:
The stress test case must follow the following format, where xxx can be a combination of any alphanumeric, but the first letter cannot be a lowercase letter
Func benchmarkxxx (b *testing. B) {...}
go test
The function of the stress test will not be performed by default, if the stress test is to be performed with parameters -test.bench
, syntax: -test.bench="test_name_regex"
For example, to go test -test.bench=".*"
test all of the stress test functions
- In the stress test case, remember to use in the loop body so that the
testing.B.N
test can run normally
- The file name must also
_test.go
end With
Here we create a new stress test file, Webbench_test.go, as shown below:
Package Gotestimport ( "testing") func benchmark_division (b *testing. B) { for I: = 0; i < B.N; i++ {//use B.N for looping Division (4, 5) }}func Benchmark_timeconsumingfunctio N (b *testing. B) { b.stoptimer ()//Call this function to stop the time count of the stress test //Do some initialization work, such as reading file data, database connection and so on,//so that these times do not affect the performance of our test function itself B.starttimer ()//Restart time for I: = 0; i < B.N; i++ { Division (4, 5)} }
We execute go test -test.bench=".*"
the command and see the following results:
Passbenchmark_division 500000000 7.76 ns/opbenchmark_timeconsumingfunction 500000000 7.80 Ns/opok gotest 9.364s
The above results show that we did not perform any TestXXX
unit test functions, the results show only the pressure test function, the first shows the Benchmark_Division
execution of 500 million times, the average time of execution is 7.76 nanoseconds, the second shows that the Benchmark_TimeConsumingFunction
execution of 500000000, The average execution time per time is 7.80 nanoseconds. The last bar shows the total execution time.
As we execute go test -test.bench=".*" -count=5
the command, we can see the following result: (use-count to specify how many times to execute)
passbenchmark_division-2 300000000 4.60ns/opbenchmark_division-2 300000000 4.57ns/opbenchmark_division-2 300000000 4.63ns/opbenchmark_division-2 300000000 4.60ns/opbenchmark_division-2 300000000 4.63ns/opbenchmark_timeconsumingfunction-2 300000000 4.64ns/opbenchmark_timeconsumingfunction-2 300000000 4.61ns/opbenchmark_timeconsumingfunction-2 300000000 4.60ns/opbenchmark_timeconsumingfunction-2 300000000 4.59ns/opbenchmark_timeconsumingfunction-2 300000000 4.60ns/Opok _/home/diego/gowork/src/app/testing -.546s
go test -run=文件名字 -bench=bench名字 -cpuprofile=生产的cprofile文件名称 文件夹
Example:
There is a popcnt folder under Testbenchmark, and there are files in popcnt popcunt_test.go
➜ Testbenchmark lspopcnt
Popcunt_test.go's Asking price content:
ackage Popcntimport ("Testing")ConstM1 =0x5555555555555555ConstM2 =0x3333333333333333ConstM4 =0x0f0f0f0f0f0f0f0fConstH01 =0x0101010101010101func popcnt (x UInt64) UInt64 {x-= (x >>1) &M1 x= (x & m2) + ((x >>2) &m2) x= (x + (x >>4)) &M4return(x * h01) >> About}func benchmarkpopcnt (b*testing. B) { forI: =0; i < B.N; i++{x:=I x-= (x >>1) &M1 x= (x & m2) + ((x >>2) &m2) x= (x + (x >>4)) &M4 _= (x * h01) >> About }}
Then run go test-bench= ". *"-cpuprofile=cpu.profile./popcnt
➜testbenchmark Go test-bench=".*"-cpuprofile=cpu.profile./popcnttesting:warning:no tests to runpassbenchmarkpopcnt-8 1000000000 2.01ns/Opok App/testbenchmark/popcnt2. 219s➜testbenchmark lltotal6704drwxr-xr-x5Diego Staff the 5 6 -: $. DRWXR-xr-x3Diego Staff102 5 6 One: A ..-rw-r--r--1Diego Staff5200 5 6 -: $CPU.PROFILEDRWXR-xr-x4Diego Staff136 5 6 One: -popcnt-rwxr-xr-x1Diego Staff3424176 5 6 -: $Popcnt.test➜testbenchmark
Production Cpu.profile asking price and Popcnt.test file
➜testbenchmark lltotal6704drwxr-xr-x5Diego Staff the 5 6 -: $. DRWXR-xr-x3Diego Staff102 5 6 One: A ..-rw-r--r--1Diego Staff5200 5 6 -: $CPU.PROFILEDRWXR-xr-x3Diego Staff102 5 6 -: onpopcnt-rwxr-xr-x1Diego Staff3424176 5 6 -: $Popcnt.test➜testbenchmark
Go tool pprof popcnt.test cpu.profile Enter interactive mode
➜testbenchmark Go tool pprof popcnt.test cpu.profileentering interactive mode (type" Help" forcommands) (pprof) Top1880ms of 1880ms Total ( -%) Flat Flat% sum% cum cum%1790ms95.21%95.21% 1790ms95.21% app/testbenchmark/popcnt. benchmarkpopcnt 90ms4.79% -% 90ms4.79%Runtime.usleep0 0% -% 1790ms95.21%Runtime.goexit0 0% -% 90ms4.79%Runtime.mstart0 0% -% 90ms4.79%Runtime.mstart10 0% -% 90ms4.79%Runtime.sysmon0 0% -% 1790ms95.21% testing. (*B). Launch0 0% -% 1790ms95.21% testing. (*B). Runn (pprof)
Go tool pprof--web popcnt.test cpu.profile into Web mode
$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile
There are several output types available, the most useful being the following:--text,--web and--list. Run go tool pprof
to get the most complete list.
Summary
By learning about unit tests and stress tests, we can see that the testing
package is lightweight, that writing unit tests and stress test cases is very simple, and that it is easy to test with the built-in go test
commands so that every time we modify the code, we execute the Go Test can simply complete the regression test.