introduce
This is a note I made while watching the video on station B. This chapter is the unit test of Glang
For the supporting video, go to Station B to search for it yourself [go language] , the highest playback volume is
The comments inside may not be right, welcome to point out ╰(°▽°)╯
(11), unit test
First, look at a demand
In our work, we will encounter such a situation, which is to confirm whether the result of a function or a module is correct, such as:
Second, the traditional method
1. The traditional way to test
In the main function, call the addUpper function to see if the actual output result is consistent with the expected result. If it is consistent, the function is correct, otherwise the function has an error, and then correct the error
code:
package main import "fmt" //a function under test func addUpper(n int) int { res := 0 for i := 1; i <= n; i++ { //i := 1; i <= n-1; i++ res += i } return res } func main() { //The traditional test method is to use it in the main function to see if the result is correct res := addUpper(10) if res != 55 { fmt.Printf("addUpper error return value=%v expected value=%v", res, 55) } else { fmt.Printf("addUpper correct return value=%v expected value=%v", res, 55) } }
2. Analysis of shortcomings of traditional methods
- Inconvenient, we need to call it in the main function, so we need to modify the main function, if the project is running now, we may stop the project.
- It is not conducive to management, because when we test multiple functions or multiple modules, we need to write in the main function, which is not conducive to our management and clear thinking
- Lead unit tests. -> testing The testing framework can solve the problem very well.
3. Unit testing
1. Basic introduction
The Go language comes with a lightweight testing framework testing and the built-in go test command to implement unit testing and performance testing. The testing framework is similar to testing frameworks in other languages. You can write tests for corresponding functions based on this framework. Use cases, you can also write corresponding stress test cases based on this framework. Through unit testing, the following problems can be solved:
- Make sure each function is runnable and the result is correct
- Make sure the code you write performs well
- Unit testing can detect logic errors in program design or implementation in a timely manner, so that problems can be exposed early, and it is convenient to locate and solve problems. The focus of performance testing is to find some problems in program design, so that programs can run smoothly under high concurrency. keep it steady
2. Quick Start
Use Go's unit tests to test the addUpper and sub functions.
Special note: During testing, it may be necessary to temporarily exit 360. (Because 360 may think that the generated test case program is a Trojan horse)
Demonstrate how to unit test:
cal.go
package cal //first function under test func addUpper(n int) int { res := 0 for i := 1; i <= n-1; i++ { res += i } return res } //The second function under test func getHub(a int, b int) int { return a + b }
cal_test.go
package cal import "testing" //Introduce go's testing package //Write a test case to test whether addUpper is correct func TestAddUpper(t *testing.T) { //transfer res := addUpper(10) if res != 55 { t.Fatalf("AdUpper(10) execution error, return value=%v expected value=%v", res, 55) } //If correct, output the log t.Logf("AdUpper(10) execute correctly...") }
sub_test.go
package cal import "testing" func TestGetHub(t *testing.T) { //Write test cases to test whether getHub is correct res := getHub(2, 3) if res != 5 { t.Fatalf("getHub(2,3)The calculation is wrong, the expected value is=%v actual value=%v", 5, res) } //correct output log t.Logf("getHub(2,3) execute correctly...") }
Schematic diagram of the operating principle of unit testing:
3. Quick start summary
-
Test case file names must end with _test.go. Such as cal_test.go, cal is not fixed.
-
The test case function must start with Test, which is generally Test+the name of the function to be tested, such as TestAddUpper
-
The formal parameter type of TestAddUpper(t *tesing.T) must be *testing.T [Look at the manual]
-
In a test case file, there can be multiple test case functions, such as TestAddUpper, TestSub
-
Run test case command
(1) cmd> go test [If the operation is correct, there is no log, and when there is an error, the log will be output]
(2) cmd> go test -v [If the operation is correct or wrong, both output logs]
-
When an error occurs, you can use t.Fatalf to format the error message and exit the program
-
The t.Logf method can output the corresponding log
-
The test case function is not placed in the main function, but it is also executed. This is the convenience of the test case [schematic].
-
PASS indicates that the test case runs successfully, and FAIL indicates that the test case fails to run
-
To test a single file, be sure to bring the original file to be tested
go test -v cal_test.go cal.go
-
test a single method
go test -v -test.run TestAddUpper
4. Comprehensive case
monster.go
package monster import ( "encoding/json" "fmt" "io/ioutil" ) type monster struct { Name string `json:"name"` Age int `json:"age"` Skill string `json:"skill"` } //Bind the method store to Monster, you can serialize a Monster variable (object) and save it to a file func (this1 *monster) Store() error { //Serialize first data, err := json.Marshal(this1) if err != nil { fmt.Println("Serialization failed:", err) return err } //save to file filePath := "E:/testback/monster.json" err = ioutil.WriteFile(filePath, data, 0666) //write json if err != nil { fmt.Println("Failed to save file:", err) return err } return err } //And deserialize it into a Monster object, check the deserialization, the name is correct func (this1 *monster) ReStore() error { //1. Read the serialized string from the file filePath := "E:/testback/monster.json" data, err := ioutil.ReadFile(filePath) //read json file if err != nil { fmt.Println("Failed to read file:", err) return err } //2. Deserialize the data err = json.Unmarshal(data, this1) if err != nil { fmt.Println("Deserialization failed:", err) return err } return err }
monster_test.go
package monster import ( "testing" ) //Test the Store function func TestStore(t *testing.T) { //Create a Monster instance monster := monster{ Name: "red boy", Age: 500, Skill: "sharp eyes", } err := monster.Store() //Call the Store function and return error to err if err != nil { t.Fatalf("monster.Store()mistake. . .") } t.Logf("monster.Store() test was successful") } //Test the ReStore function func TestRestore(t *testing.T) { //Create a Monster instance first, no need to specify the value of the field monster := monster{} err := monster.ReStore() //Call the Store function and return error to err if err != nil { t.Fatalf("monster.ReStore()mistake. . .") } //further judgment if monster.Name != "red boy" { t.Fatalf("monster.ReStore()mistake. . . expected value=%v actual value=%v", "red boy", monster.Name) } t.Logf("monster.Store() test was successful") }
After the new version is revised
monster.go
package monster import ( "bufio" "encoding/json" "fmt" "io" "os" ) type monster struct { Name string `json:"name"` Age int `json:"age"` Skill []string `json:"skill"` } // Bind the method store to Monster, you can serialize a Monster variable (object) and save it to a file func (this1 *monster) Store() error { //Serialize first data, err := json.Marshal(this1) if err != nil { fmt.Println("Serialization failed:", err) return err } //save to file filePath := "E:/testback/monster.json" // err = ioutil.WriteFile(filePath, data, 0666) //write json file, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if err != nil { fmt.Println("Failed to save file:", err) return err } defer file.Close() writer := bufio.NewWriter(file) writer.WriteString(string(data)) writer.Flush() return err } // And deserialize it into a Monster object, check the deserialization, the name is correct func (this1 *monster) ReStore() error { //1. Read the serialized string from the file filePath := "E:/testback/monster.json" // data, err := ioutil.ReadFile(filePath) //read json file file, err := os.Open(filePath) if err != nil { fmt.Println("Failed to read file:", err) return err } reader := bufio.NewReader(file) for { str, err := reader.ReadString('}') if err == io.EOF { break } err = json.Unmarshal([]byte(str), this1) if err != nil { fmt.Println("Deserialization failed:", err) return err } } //2. Deserialize the data // err = json.Unmarshal([]byte(str), this1) // if err != nil { // fmt.Println("Deserialization failed:", err) // return err // } fmt.Println("1111111111") file.Close() return err }
monster_test.go
package monster import ( "fmt" "testing" ) // Test the Store function func TestStore(t *testing.T) { //Create a Monster instance monster := monster{ Name: "red boy", Age: 500, //Skill: "Hundian Ling", //"Weapon", //"Huntian Ling", "Flame Gun", } monster.Skill = append(monster.Skill, "Kunten Aya") monster.Skill = append(monster.Skill, "flame gun") err := monster.Store() //Call the Store function and return error to err if err != nil { t.Fatalf("monster.Store()mistake. . .") } t.Logf("monster.Store() test was successful TestStore The result is=%v", monster) } // Test the ReStore function func TestRestore(t *testing.T) { //Create a Monster instance first, no need to specify the value of the field monster := monster{} err := monster.ReStore() //Call the Store function and return error to err if err != nil { t.Fatalf("monster.ReStore()mistake. . . The result is=%v \n The error is:%v", monster, err) fmt.Println(err) } //further judgment if monster.Name != "red boy" { t.Fatalf("monster.ReStore()mistake. . . expected value=%v actual value=%v", "red boy", monster.Name) } t.Logf("monster.Store() test was successful TestRestore The result is=%v", monster) }
