This is a creation in Article, where the information may have evolved or changed.
6. Program Testing and documentation
6.1 Program Testing
The Go Test command is available in the goes language, which not only tests the code package, but also tests individual source files, as long as there are test source files for those tests. In addition, the go language provides a code package testingfor testing in the standard library, which provides everything you need to write test source files.
1. Functional Testing
The test source file should always be in the same code package as the source file it is testing. The APIin standard library code package testing is always used when writing test source files. The testing package provides automated test support for the Go language code package. It is intended to be used in conjunction with the go Test command to automate any test function in the target code package.
(1). Writing Functional Test functions
In the test source file, the functional test program for program entities in other source files is always in the function unit. The name and signature of the function that is used to test the program entity function is as follows:
*testing.T)
wherexxx should be a combination of letters or numbers beginning with capital letters, typically replacing xxx with the name of the program entity being tested. Can take advantage of *testing. some methods on the T-type parameter T record and control the process of functional testing. Information recorded using the method on the value of T is printed to the standard output after the test is finished (regardless of success or failure).
(2) General records
The log and Logf methods on the parameter T are generally used to record some general information to show the running process of the test program and the real-time state of the program entity being tested. The invocation statement is as follows:
t.Log("Tomorrow is a ""good ""day ")//类似于fmt.Printlnt.Logf("Tomorrow is a %s"" good day ")//类似于fmt.Printf
Using the go test–v command, both will print the following information:
Xxx_test.go:10:tomorrow is a good day
Xxx_test.go:11:tomorrow is a good day
xxx_test.go:represents the name of the test source file where the invocation statement resides and the line number that appears.
(3). Error logging
The error and Errorf methods on the parameter T are used for the fault message. When the state of the program entity being tested is incorrect, the current error status is recorded in a timely manner using the t.error or T.errorf method. For example:
actLen := len(s)if actLen != expLen { t.Errorf("Error: The length of slice should be %d but %d.\n", expLen, actLen)}
Calling the T.error method is equivalent to calling the T.Log and t.fail methods successively, whereas calling the T.errorf method is equivalent to T.LOGF and The C5>t.fail method is called.
(4). Fatal Error Record
The Fatal and fatalf methods on the parameter T are used to record the status error of the fatal program entity. The so-called fatal error is the error that makes the test impossible to proceed. For example:
ifnil { t.Fatalf("Listener startup failing! (addr=%s)!\n", serverAddr)}
Calling the t.fatal method is equivalent to calling the T.Log and T.failnow methods successively, whereas calling the T.fatalf method is equivalent to T. The Logf and T.failnow methods are called.
(5). Failure token
If you need to mark the test in the current test function as a failure, then you need to use the t.fail method. Calls to the T.fail method do not terminate the execution of the current test function. However, the test results for this function have been marked as failed.
(6). Immediate Failure token
The T.failnow method differs from T.fail in that it terminates the execution of the current test function as soon as it is called. This will allow the current Test runner to go on to perform other test functions instead.
Note: the t.failnow method can only be called in the Goroutine that runs the test function, not in the Goroutine created by the test code. However, calling the T.failnow method in other goroutine does not cause any errors, but it does not produce any effect.
(7). Failure judgment
After calling the t.failed method, you get a result value of type bool that represents whether the test in the current test function has been marked as failed.
(8). Ignore test
The purpose of calling the T.skipnow method is to mark the current test function as being ignored, and immediately terminate the function's execution, and the current Test runner will go to execute the other test function instead. As with the T.failnow method, theT.skipnow method can only be called in the Goroutine that runs the test function.
Calling the T.skip method is equivalent to calling the T.Log and T.skipnow methods successively, whereas calling the T.skipf method is equivalent to T.LOGF and The C9>t.skipnow method is called.
The result value of the t.skipped method tells whether the current test has been ignored.
(9). Running in parallel
The call to the T.parallel method causes the current test function to be marked to run in parallel. This enables the test runner to execute it concurrently and other test functions that can run in parallel.
(10). Function test Run
Using the goc2p Project's code package cnet/ctcp and Pkgtool as an example, here is the download address:
Https://github.com/hyper-carrot/go_command_tutorial
The code package contains only a test source file named tcp_test.go . The test source file contains two test functions. One is a functional test function named Testprimefuncs , and one is a benchmark function named Benchmarkprimefuncs .
Use the Go Test command to run the test results in the cnet/ctcp package as follows:
If you want to run only part of the test in a code package, there are two ways to choose:
The first is that the Go test command is followed by testing the source file and its test source file as parameters, not the code package. For example:
Go Test envir_test.go Envir.go
The second way is to use the tag -run . The value of the -run tag should be a regular expression. A functional test function with a name that matches this regular expression is executed during the test run of the second time. Run as follows:
The Code package test source file tcp_test.go function test function Testprimefuncs will be executed. However, when the regular expression is changed to "Prima" , there is no function test function that matches the name because there is no cnet/ctcp package. For example:
In the go language, the test process can be recorded by means of T.Log and t.logf . However, the information printed using this method is not displayed by default. Therefore, you need to mark - v , which prints all logs that were logged during the test run, after the test runs are finished. For testing purposes, it is strongly recommended to use the method on the value of the method parameter T in the test source file to record the log.
Look at one of the following examples, while testing the code package cnet/ctcp and the code package Pkgtool, as follows:
(11). About the time of the test run
Now consider a test scenario in which a test function contains a period of time-consuming code and requires strict enforcement of the time limit for executing the test function. A run-time panic can be raised when the go Test command is executed with the tag -timeout, and the time limit testing that is represented by its value is not finished. The value of the -timeout tag is the type time . Duration The time notation that can be accepted. For example,1h20s represents 1 hours and 20 seconds ,2h45m represents 2 hours and 45 minutes , and200ms represents 200 milliseconds .
Valid unit of Time
Time Unit |
string Notation |
Na-Sec |
"NS" |
Microseconds |
"Us" or "µs" |
Milliseconds |
"MS" |
Seconds |
"S" |
Minutes |
"M" |
Hours |
"H" |
It takes about 2 seconds for the function test function to run before running the code package cnet/ctcp . Now use the -timeout flag to set the test time limit to a maximum of milliseconds and run the test. As follows:
e:\software\go\goc2p\src>go test-timeout 100ms cnet/ctcp
Panic:test timed out after 100ms
...
FAIL cnet/ctcp 0.715s
If you just want the test to end as soon as possible, use the -short tag to mean that the tests you want to run will shorten their run time. The code package testing has a function named short . This function returns a value of type bool after it is called. This value indicates whether the -short tag was added when the go Test command was executed. If the bool value returned by this function is true , then you can trim the test code to shorten the test run time, depending on the situation. You can write a similar code in a functional test function:
if testing. Short () {multisend (serveraddr, , 1 , ( Span class= "Hljs-number" >2 * time . second ), Showlog)} else {multisend ( SERVERADDR, "SenderT1" , 2 , ( 2 * time . second ), Showlog) multisend (serveraddr, "SenderT2" , 1 , (2 * Time . second ), Showlog)}
This code from the test source file tcp_test.go test function Testprimefuncs, but made a change, focus on the function multisend , according to testing. The returned result value of short () makes a different strategy.
(12). Concurrent execution of tests
If a functional test runs on a computer that has a multi-core CPU or multiple CPUs, you can perform the test in a concurrent manner. With the -parallel tag, you can set the maximum number of function test functions that are allowed to execute concurrently. But being able to be a function test function that is executed concurrently requires a prerequisite: Add code t.parallel () at the beginning of the function test function. When calling the T.parallel method, the test runner executing the function test function blocks here and waits for other test functions that also satisfy the concurrency execution condition. When all the test functions that need to be executed in parallel are inventoried and blocked, the command program executes all or part of the code that follows the statement T.parallel () in the function test according to the value of the -parallel tag.
The default value of the -parallel tag is the value set by the function Gomaxprocs of the standard library's code package runtime . The function is to set the maximum number of concurrent processing for the go language. In fact, even if the value of the -parallel tag is greater than the maximum number of concurrent processing in the Go language, the number of function test functions that can be executed concurrently is no more than that, so in general it is not necessary to include the -parallel tag in the command. It would be nice to have its actual value as the default value. However, it is important to note that the default value for the maximum number of concurrent processing in the Go language is 1 . If you want the code in some test functions to be executed concurrently, it is necessary to set the appropriate maximum concurrent processing number of the go language in the init function of the test source file and add the statement T.parallel ()to these test functions.
2. Benchmark Test
The so-called benchmark test (Benchmarktest, referred to as BMT) refers to a number of scientific means to achieve a class of test objects of a certain performance indicators of measurable, repeatable and comparable to the test. Many times, benchmarks have been narrowly referred to as performance testing.
(1). Writing benchmark functions
As with functional testing, the benchmark program for program entities in other source files is also measured in the test function. The name and signature of a benchmark function is as follows:
*testing.B)
(2). About Timers
In *testing. in type B, there are 3 methods associated with timers that are starttimer,stoptimer , and Resettimer . These 3 methods are used to manipulate the timer of a benchmark function. The purpose of this timer is to calculate the execution time of the current benchmark function.
Calling the B.starttimer method means starting the timing of the execution of the current test function. It is always called automatically when it starts to execute the benchmark function. The point of this method being exposed is that the timer restarts after it is stopped. Call the B.stoptimer method to stop the timer for the current test function. For example:
package bmtimport ( "testing" "time"*testing.B) { customTimerTag := false if customTimerTag { b.StopTimer() } b.SetBytes(12345678) time.Sleep(time.Second) if customTimerTag { b.StartTimer() }}
As the file named bmt_test.go is stored in the TESTING/BMT code package for the workspace, run the benchmark test as follows:
Now change the value of the customtimertag variable to true , and then run the test as follows:
The output from the last two rows can be seen differently from the two above. In the second, the 3 parts of the penultimate line represent the name of the current test function, the number of operations and the average time-consuming operation. Where the number of operations is the number of times the current benchmark function is executed, and the average time spent on the operation is the average execution of the current benchmark function.
Similarly, the second-to-last line of two runs shows that when Customtimertag is true , the benchmark function Benchmark can be executed multiple times, and when Customtimertag when false , it tends to get only one execution opportunity. These are due to one of the limitations in the testing package: Only the benchmark function executes once if the benchmark function has a single execution time that exceeds the specified value (the default is 1 seconds or can be customized by the tag -benchtime ). That is, the Test runner executes a benchmark function as many times as possible, without exceeding the maximum execution time.
When Customtimertag is true , the call statement is time . Sleep (time. Second) before and after, respectively, stop and restart the timer for the Benchmark function, which is equivalent to not taking time . Sleep (time. Second) The execution time of the statement is calculated within the execution time of the Benchmark function, and the time to execute the Benchmark function is largely negligible (can be ns/op from 0.00 ), so that the Test runner will repeatedly execute the Benchmark function until the cumulative execution time of the time limit is reached.
When Customtimertag is false , the statement time is invoked . Sleep (time. Second) Let the current test program "Rest" for1 seconds, theBenchmark function of the single execution time will certainly be greater than 1 seconds. Therefore, the Test runner does not perform a second time on the Benchmark function.
For method B.resettimer , when called, resets the timer of the current benchmark function to reset the function's execution time to 0, which is equivalent to putting the current function in the b.resettimer The execution time of all statements before the statement is subtracted from the execution time of the function.
(3). About Memory allocation statistics
The meaning of method B.reportallocs is to determine if there is a -benchmem tag behind the Go test command that initiates the current tests. It returns a result value of type bool .
The b.setbytes method accepts a value of type Int64 , which is used to record the number of bytes processed in a single operation.
When Customtimertag is false, there is a section in the line of information about the operation of the Benchmark function in the run- 12.34mb/s . It means the number of bytes processed per second (in megabytes ). This number is actually equal to the number of times per second that the Test runner invokes the B.setbytes method in the process of executing (possibly multiple) Benchmark functions multiplied by the incoming integer.
First imagine a scenario in which a function that writes data to a file system is tested in the benchmark function Benchmark . After the write succeeds, the b.setbytes method is called and the number of bytes actually written is passed as a parameter. With xxx MB/s in the test results information, you can tell how many megabytes ( MB ) of data The function can write to the file system per second.
From the above summary, theb.setbytes method can count the actual performance of the program entity being tested from the input and output (IO) angle.
(4). Operation of benchmark tests
In the previous test, theGo Test command ran only the functional tests in the cnet/ctcp package. The following is a description of the benchmark tag for the go Test command.
Tag Name |
Tag Description |
-bench RegExp |
By default, the Go Test command does not run any benchmarks, but you can use the tag to perform a match to the "RegExp" The regular expression of the benchmark function, "regexp" can be replaced by any regular expression. If you need to run all of the benchmark functions, Add –bench. or –bench=. or –bench= "." |
-benchmem |
Include memory allocation statistics for benchmark tests in output content |
-benchtime T |
The number of operations used to indirectly control a single benchmark function. The "T" here refers to the cumulative time limit for executing a single test function. The content at "T" uses the type time. Duration acceptable time notation. The default value for "t" is 1s |
Run the baseline test against the code package cnet/ctcp as follows:
struct type testing. the field N of B can be used to set the number of repeated executions of a block of code in a benchmark function. For example:
fori0b.i{ //测试代码}
Run as follows:
For the specific algorithm that calculates the value of N , you can view the relevant code in the source file benchmark.go of the testing package of the standard library.
The -benchmem tag is used when you want to see the number of operations of the benchmark function and the average time it takes for the operation to get the memory allocation in the process. For example, the following:
"23416 b/op" is an average of 23416 bytes Allocated per operation. "109 allocs/op" is the average number of 109 times each operation allocates memory.
The go Test command can also accept a custom test run count and change the max concurrent processing number of the go language during the test run -cpu , the -cpu tag can be a list of integers with multiple integers separated by commas. The -cpu tag is handled in the opposite way as the -parallel tag, and the-parallel tag defaults to the maximum number of concurrent processing in the go language, while the -cpu tag sets it directly. However, the set operation of the maximum number of concurrent processing of Go languages raised by the -cpu tag does not affect the default value of the -parallel tag. Because the value of the -parallel tag is set when the test run program is initialized. If the -parallel tag is not explicitly added to the go Test command, its value is set to the maximum number of concurrent processing in the go language at the time of the Test runner's initialization. At this point, the test program runs without parsing the value of the -cpu tag (if any) into an array of integers, and cannot use the integers in this array to set the maximum number of concurrent processing in the go language.
Use the -cpu tag to run as follows:
The number of times the Test runner performs the benchmark function Benchmarkprimefuncs is 7, which is the value of the -cpu tag 1,2,4,8,12,16,20 Corresponds to 7 numbers in the. The above only shows the benchmark test run record, the same side also called 7 function test function Testprimefuncs .
As on the run, the end of the countdown line contains a row of runtime environment information:[Gomaxprocs=20, Num_cpu=4, num_goroutine=2], for the first Gomaxprocs Represents the maximum number of concurrent processing in the Go language, where "Num_cpu" represents the total CPU cores of the current computer, here is 4,"Num_goroutine" Represents the number of concurrent programs at the current moment, here is 2.
tags related to concurrency processing
Tag Name |
using the example |
Description |
-parallel |
-parallel 4 |
Function: Sets the maximum number of function test functions that can be executed concurrently Default value: Call runtime. Gomaxprocs (0) results, that is, the maximum number of concurrent processing in the Go language Prerequisite: The functional test function needs to call the struct testing at the beginning. Parallel method for parameter values of type T Test in effect: Functional testing |
-cpu |
-cpu 1,2,4 |
Function: Depending on the value of the tag, the iteration sets the maximum number of concurrent processing for the go language and performs all functional tests or all benchmarks. The number of iterations is consistent with the number of integers in the tag value Default value: "", which is an empty string Prerequisites: None Test in effect: Functional testing and benchmark testing |
Note: The scopes of -cpu and -parallel tags are code packages that can only be used to control the flow of tests within a code package. If you use the go Test command to start a test of multiple code packages, the functional tests in each code package are always concurrency-capable, and benchmark tests are always executed serially. If you consider the running process of all tests for a code package as a whole, if you add the -bench tag when you execute the go test command, the test run process for each code package will be executed serially, otherwise they will be executed concurrently. However, the action to print the Test record and result information is performed strictly according to the code package that follows the go Test command from left to right.
This article explains the functional testing and benchmarking of the Go Language Program test, and the next chapter continues to explain the relevant knowledge of the Go Language program test.
Finally, we enclose the local Go language community (one for each update)
golangtc.com: The community is one of the most active in the Chinese community of Go languages. We can learn a lot about the go language. Website: http://www.golangtc.com