The first test “Hello Test!”
First, create the hello directory under our $GOPATH/src directory as the root directory of all the sample code involved in this article.
Then, create a new file named and define a functionhello()
, the function is to return a sentence spliced by several words:
package hello func hello() string { words := []string{"hello", "func", "in", "package", "hello"} wl := len(words) sentence := "" for key, word := range words { sentence += word if key < wl-1 { sentence += " " } else { sentence += "." } } return sentence }
Next, create a new file named hello_test.go and fill in the following content:
package hello import ( "fmt" "testing" ) func TestHello(t *) { got := hello() expect := "hello func in package hello." if got != expect { ("got [%s] expected [%s]", got, expect) } } func BenchmarkHello(b *) { for i := 0; i < ; i++ { hello() } } func ExampleHello() { hl := hello() (hl) // Output: hello func in package hello. }
Finally, open the terminal, enter the hello directory, and entergo test
Command and press Enter, you can see the following output:
PASS ok hello 0.007s
Writing test code
Golang's test code is located in the source file with the name ending with _test.go in the source code of a package. The test code includes test functions, test auxiliary code and example functions. The test functions include functional test functions starting with Test and performance test functions starting with Benchmark. The test auxiliary code is a public function, initialization function, test data, etc. serving the test function, and the example function is a function that starts with Example that explains the usage of the function being tested.
In most cases, the test code is as part of a package, meaning it can access elements that are not exportable in the package. However, when needed (such as avoiding circular dependencies), you can also modify the package name of the test file, such as the test file of package hello, and the package name can be set to package hello_test.
Functional test function
Functional testing functions need to receive a single parameter t of type *, which is used to manage test status and support formatted test logs. The test logs are accumulated during the test execution and are output to the standard error output after completion.
Here are the usages of common methods of types excerpted from the Go standard library:
When the execution result of a test case in the test function does not match the expected result, it is called()
or()
Method logs and marks test failure
# /usr/local/go/src/bytes/compare_test.go func TestCompareIdenticalSlice(t *) { var b = []byte("Hello Gophers!") if Compare(b, b) != 0 { ("b != b") } if Compare(b, b[:1]) != 1 { ("b > b[:1] failed") } }
use()
and()
Method: After a test case fails, the test function will be popped up.
# /usr/local/go/src/bytes/reader_test.go func TestReadAfterBigSeek(t *) { r := NewReader([]byte("0123456789")) if _, err := (1<<31+5, os.SEEK_SET); err != nil { (err) } if n, err := (make([]byte, 10)); n != 0 || err != { ("Read = %d, %v; want 0, EOF", n, err) } }
use()
and()
Method, skip the execution of a test case
# /usr/local/go/src/archive/zip/zip_test.go func TestZip64(t *) { if () { ("slow test; skipping") } const size = 1 << 32 // before the "END\n" part buf := testZip64(t, size) testZip64DirectoryRecordLength(buf, t) }
Passed during the execution of test cases()
and()
Logging
# /usr/local/go/src/regexp/exec_test.go func TestFowler(t *) { files, err := ("testdata/*.dat") if err != nil { (err) } for _, file := range files { (file) testFowler(t, file) } }
use()
Mark test functions that need to be executed concurrently
# /usr/local/go/src/runtime/stack_test.go func TestStackGrowth(t *) { () var wg // in a normal goroutine (1) go func() { defer () growStack() }() () // ... }
Performance Test Function
The performance test function needs to receive a single parameter b of type *, and the performance test function needs to be called cycled in the performance test function. Types are used to manage test time and iteration run times, and also support the same way to manage test status and formatted test logs. The difference is that the logs will always be output.
Here are the usages of common methods of types excerpted from the Go standard library:
Called in a function()
, enable memory usage analysis
# /usr/local/go/src/bufio/bufio_test.go func BenchmarkWriterFlush(b *) { () bw := NewWriter() str := ("x", 50) for i := 0; i < ; i++ { (str) () } }
pass()
、()
、()
to stop, reset, start time elapse and memory allocation count
# /usr/local/go/src/fmt/scan_test.go func BenchmarkScanInts(b *) { () ints := makeInts(intCount) var r RecursiveInt for i := - 1; i >= 0; i-- { buf := (ints) () scanInts(&r, buf) () } }
Call()
Record the number of bytes processed in an operation
# /usr/local/go/src/testing/ func BenchmarkFields(b *) { (int64(len(fieldsInput))) for i := 0; i < ; i++ { Fields(fieldsInput) } }
pass()
Methods and * typesNext()
Method to execute the object to be tested concurrently
# /usr/local/go/src/sync/atomic/value_test.go func BenchmarkValueRead(b *) { var v Value (new(int)) (func(pb *) { for () { x := ().(*int) if *x != 0 { ("wrong value: got %v, want 0", *x) } } }) }
Test auxiliary code
Test-assisted code is caused by code reuse and code quality considerations during the writing of test code. It mainly includes the following aspects:
Introduce dependable external packages, such as testing packages required for each test file:
# /usr/local/go/src/log/log_test.go: import ( "bytes" "fmt" "os" "regexp" "strings" "testing" "time" )
Define constants and variables used multiple times, test case data, etc.:
# /usr/local/go/src/log/log_test.go: const ( Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]` Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]` Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]` Rline = `(57|59):` // must update if the calls to / below move Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline ) // ... var tests = []tester{ // individual pieces: {0, "", ""}, {0, "XXX", "XXX"}, {Ldate, "", Rdate + " "}, {Ltime, "", Rtime + " "}, {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "}, {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time {Llongfile, "", Rlongfile + " "}, {Lshortfile, "", Rshortfile + " "}, {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile // everything at once: {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "}, {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "}, }
Like ordinary Golang source code, the init function can also be defined in the test code. The init function will be automatically called after introducing external packages, defining constants, and declaring variables. You can write test-related initialization code in the init function.
# /usr/local/go/src/bytes/buffer_test.go func init() { testBytes = make([]byte, N) for i := 0; i < N; i++ { testBytes[i] = 'a' + byte(i%26) } data = string(testBytes) }
Encapsulate common functions dedicated to testing, structures dedicated to abstract testing, etc.:
# /usr/local/go/src/log/log_test.go: type tester struct { flag int prefix string pattern string // regexp that log output must match; we add ^ and expected_text$ always } // ... func testPrint(t *, flag int, prefix string, pattern string, useFormat bool) { // ... }
Sample Function
The sample function does not need to receive parameters, but requires the commented Output: mark to illustrate the output value of the sample function. The sample function without specifying the Output: mark or the output value is empty will not be executed.
The example function needs to be a method that belongs to a package/function/type/type. The specific naming rules are as follows:
func Example() { ... } # package example functionfunc ExampleF() { ... } # Example function of function Ffunc ExampleT() { ... } # Example function of type Tfunc ExampleT_M() { ... } # Example function of M method of type T # Multi-example function requires an underscore and a suffix starting with lowercase lettersfunc Example_suffix() { ... } func ExampleF_suffix() { ... } func ExampleT_suffix() { ... } func ExampleT_M_suffix() { ... }
The go doc tool parses the function body of the example function as the usage of the corresponding package/function/type/type method.
For relevant instructions for testing functions, you can use go help testfunc to view the help document.
Use the go test tool
In Golang, go test is used to execute the test code, open the shell terminal, enter the directory where the package that needs to be tested is located to execute go test, or execute it directly.go test $pkg_name_in_gopath
Tests can be performed on the specified package.
Through the shapego test /tabalt/...
The command can be executed$GOPATH//tabalt/
Tests of all projects in the directory.go test std
The command can execute all tests of the Golang standard library.
If you want to see which test functions are executed and the execution results of the functions, you can use the -v parameter:
[tabalt@localhost hello] go test -v === RUN TestHello --- PASS: TestHello (0.00s) === RUN ExampleHello --- PASS: ExampleHello (0.00s) PASS ok hello 0.006s
Suppose we have many functional test functions, but a certain test only wants to execute some of them. You can use the -run parameter and use a regular expression to match the name of the functional test function to be executed. If the parameters are specified below, the function test function TestHello will not be executed.
[tabalt@localhost hello] go test -v -run=xxx PASS ok hello 0.006s
The performance test function will not be executed by default. You need to add the -bench parameter and specify a regular expression that matches the performance test function name; for example, if you want to execute all the performance test functions in a certain package, you can add the parameter -bench . or -bench=.
[tabalt@localhost hello] go test -bench=. PASS BenchmarkHello-8 2000000 657 ns/op ok hello 1.993s
To view the memory status during performance testing, you can add the parameter -benchmem:
[tabalt@localhost hello] go test -bench=. -benchmem PASS BenchmarkHello-8 2000000 666 ns/op 208 B/op 9 allocs/op ok hello 2.014s
Parameters -cover can be used to view the coverage of the code of the tests we wrote:
Detailed coverage information can be output to the file through -coverprofile and used go tool cover to view it. Please refer to the usagego tool cover -help
。
Morego test
The parameters and usage of the command can be passedgo help testflag
Come to view the help documentation.
Advanced testing technology
IO related tests
The commonly used error reader and Writer are implemented in the testing/iotest package, which can be used in io-related tests. Mainly:
Trigger data error dataErrReader, throughDataErrReader()
Function creation
halfReader that reads half content, throughHalfReader()
Function creation
Read a byte oneByteReader, throughOneByteReader()
Function creation
Trigger timeoutReader with timeout error, throughTimeoutReader()
Function creation
The truncateWriter that stops after writing the specified number of digits, passTruncateWriter()
Function creation
ReadLogger that records logs when reading, throughNewReadLogger()
Function creation
WriteLogger that records logs when writing, throughNewWriteLogger()
Function creation
Black box test
The testing/quick package implements practical functions Check and CheckEqual to help black box testing.
The first parameter of the Check function is the black box function f that only returns the bool value to be tested. Check will set any value for each parameter of f and call it multiple times. If f returns false, the Check function will return the error value *CheckError. The second parameter of the Check function can specify a type of config, and the nil will be used by default. The structure contains options for test run.
# /usr/local/go/src/math/big/int_test.go func checkMul(a, b []byte) bool { var x, y, z1 Int (a) (b) (&x, &y) var z2 Int (mulBytes(a, b)) return (&z2) == 0 } func TestMul(t *) { if err := (checkMul, nil); err != nil { (err) } }
The CheckEqual function compares whether the given two black box functions are equal. The function prototype is as follows:
func CheckEqual(f, g interface{}, config *Config) (err error)
HTTP testing
The net/http/httptest package provides HTTP-related code tools. Our test code can create a temporary code to test the HTTP request:
ts := ((func(w , r *) { (w, "Hello, client") })) defer () res, err := () if err != nil { (err) } greeting, err := () () if err != nil { (err) } ("%s", greeting)
You can also create a reply recorderTo detect the response content:
handler := func(w , r *) { (w, "something failed", ) } req, err := ("GET", "/foo", nil) if err != nil { (err) } w := () handler(w, req) ("%d - %s", , ())
Test process operation behavior
When our tested function has the behavior of operating processes, we can perform tests using the tested program as a child process. Here is an example:
//The process being tested exits the functionfunc Crasher() { ("Going down in flames!") (1) } //Test function of test process exit functionfunc TestCrasher(t *) { if ("BE_CRASHER") == "1" { Crasher() return } cmd := ([0], "-=TestCrasher") = append((), "BE_CRASHER=1") err := () if e, ok := err.(*); ok && !() { return } ("process ran with err %v, want exit status 1", err) }
Summarize
The above is the entire content of this article. I hope the content of this article will be helpful to everyone to learn or use Go. If you have any questions, you can leave a message to communicate.