2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
In the Go language, unit testing is implemented through the testing package in the standard library, which provides a set of functions that make writing, running, and managing unit tests simple and efficient.
Test file naming conventions
The test file naming convention in Go is to add the name of the source file being tested after it._test.go
For example, if you have a calculator.go
file, the corresponding test file should becalculator_test.go
。
Naming conventions for test functions
Test functions must start withTest
It starts with , and can be followed by any non-empty string, for exampleTestAdd
、TestSubtract
wait.
use testing.T
Making assertions and error reporting
In the test function, usetesting.T
Type parameters to manage test status and output. You can uset.Error*
、t.Fail*
etc. to indicate test failure and output relevant error information.
A calculator function is defined in the calculator package, and its implementation is as follows:
package calculator
func Add(a, b int) int {
return a + b
}
In the current directory, we create a test file called calculator_test.go and define a test function as follows:
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Add(1,2) return %d, expected %d", result, expected)
}
}
To run this unit test, you can use the go test command. In the command line, change to the directory containing calculator.go and calculator_test.go, and then executego test
, these results are as follows
go test
PASS
ok modu 0.226s
Add the following test function in calculator_test.go:
func TestAdd2(t *testing.T) {
result := Add(3, 2)
expected := 3
if result != expected {
t.Errorf("Add(1,2) return %d, expected %d", result, expected)
}
}
In order to better see the execution status of each test case in the output results, we cango test -v
Parameters to let it output complete test results.
go test -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
=== RUN TestAdd2
calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL modu 0.216s
go test -run
The command can run tests according to the specified pattern. This command supports regular expressions to select the test functions to run.
For example, after correcting the TestAdd2 use case,go tes -run=Add2
Only the TestAdd2 test case is run, and the result is
go test -run=Add2 -v
=== RUN TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok modu 0.198s
4. Skip some test cases
Added test function
func TestAdd3(t *testing.T) {
if testing.Short() {
t.Skip("short模式下会跳过该测试用例")
}
result := Add(3, 2)
expected := 5
if result != expected {
t.Errorf("Add(1,2) return %d, expected %d", result, expected)
}
}
When executinggo test -shor
t, it will skiptesting.Short()
The test case marked with
go test -short -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
=== RUN TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN TestAdd3
calculator_test.go:23: short模式下会跳过该测试用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok modu 0.635s
Through test groups and subtests, it is more friendly to add more test cases and view the results
func TestAdd(t *testing.T) {
tests := []struct {
name string
x, y int
expected int
}{
{"Add1", 1, 2, 3},
{"Add2", 3, 3, 6},
{"Add3", 4, 5, 8},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := Add(tc.x, tc.y)
if result != tc.expected {
t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
}
})
}
}
rungo test -v
,turn out
go test -v
=== RUN TestAdd
=== RUN TestAdd/Add2
=== RUN TestAdd/Add3
calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)
--- PASS: TestAdd/Add1 (0.00s)
--- PASS: TestAdd/Add2 (0.00s)
--- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL modu 0.190s
Go language naturally supports concurrency, so by addingt.Parallel()
To achieve parallelization of driver testing.
func TestAdd(t *testing.T) {
t.Parallel() // 将 TLog 标记为能够与其他测试并行运行
// 这里使用匿名结构体定义了若干个测试用例
// 并且为每个测试用例设置了一个名称
tests := []struct {
name string
x, y int
expected int
}{
{"Add1", 1, 2, 3},
{"Add2", 3, 3, 6},
{"Add3", 4, 5, 8},
}
for _, tc := range tests {
tc := tc // 注意这里重新声明tt变量(避免多个goroutine中使用了相同的变量)
t.Run(tc.name, func(t *testing.T) {
t.Parallel() // 将每个测试用例标记为能够彼此并行运行
result := Add(tc.x, tc.y)
if result != tc.expected {
t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
}
})
}
}
usego test -cover
To view test coverage
go test -cover
PASS
modu coverage: 100.0% of statements
ok modu 1.149s
When doing unit testing in Go, we usually need to use a lot of assertions because there is no official built-in assertion function.if...else...
Statement to verify the test results. However, by using third-party libraries such astestify/assert
, we can easily call a variety of commonly used assertion functions, which can not only simplify the test code, but also generate clear and easy-to-understand error description information to help us quickly locate the problem.
In the above example, we useif...else...
Statement to verify the test results
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := Add(tc.x, tc.y)
if result != tc.expected {
t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
}
})
}
Available nowtestify/assert
The above judgment process is simplified as follows:
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := Add(tc.x, tc.y)
assert.Equal(t, result, tc.expected)
})
}
testify/require
havetestify/assert
All assertion functions have the only difference thattestify/require
If a test case fails, the test will be terminated immediately.