Super parsing language

Time:2022-5-18
catalogue
  • 1、 Unit test classification and its concept
    • 1. Basic classification
    • 2. Describe the classification of unit test in detail
  • 2、 Describe each test in detail in combination with the code
    • 1. Benchmark test
    • 2. Group test and sub test
  • 3、 Pprof debugging tool
    • 1. Transfer parameters to the main function
    • 2. Pprof performance tuning

preface:

Usually write code according to needs Manual testing is often not comprehensive, and it is cumbersome to test because of the change of requirements
By completing a test function, you can greatly simplify the test steps, and only need to change the test input and expectation when the requirements need to change

1、 Unit test classification and its concept

1. Basic classification

  • The prefix of the test function is test, which is mainly used to test whether some logical behaviors of the program are correct
  • The base function name is prefixed withBenchmark It mainly tests the performance of the function
  • The prefix name of the sample function isExamplePrompt sample documents for documents

2. Describe the classification of unit test in detail

① Test function

  • Basic test of function
  • Group test of function
  • Subtest of function
  • Test function coverage (that is, how much code of the tested function is used for execution)
  • When testing, ensure that the coverage of the tested function is 100% and the coverage of the tested function is more than 60%. Otherwise, most of the written code cannot be used and needs to be optimized
    • ① Test coverage can be usedgo test -cover
    • go test -cover -coverprofile=c.out(store the test results in the file c.out)
    • Then usego tool cover -html=c.outYou can open a file to show which code has not been executed

② Benchmark test

  • What does benchmark function test do: the benchmark function will define a time period for executing the code. If the code is concise, the execution times of the tested function need to be doubled (until it reaches the expectation given by the benchmark function, and then count the total number of rounds of execution and the average time of each round)
  • When executing the benchmark function, first write the benchmark function
  • The parameters of the benchmark function are: * testing Pointer variable corresponding to B
  • A loop is carried out inside the test function, and the termination condition of the loop is b.n

2、 Describe each test in detail in combination with the code

1. Benchmark test

(1) Points needing attention of benchmark function

In the benchmark test, the algorithm of the function is often tested. Sometimes the effect of the latter algorithm will be different when the basis of the test data is different. When we need to test samples of different orders of magnitude. You can write a box as a springboard and test only the current order of magnitude of data

When testing, the command is:go test -bench=. (execute all springboard functions once) or = perform specific function test for specific function – benchtime = time (this parameter can be used to expand the time when the tested function cannot be completed within the default time of the benchmark function). When performing benchmark function test, some pre work may be required. If you feel that the pre work wastes time, you can use # B. resettimer() to reset the timer

(2) Benchmark code

The test function code is as follows:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//File name substr_ test. go
package main
 
import (
    "reflect"
    "testing"
)
func BenchmarkSubStr(b *testing.B) {
    for i := 0; i < b.N; i++ {
        res := subStr("qwe:qw:es:wqe", ":")
        if !reflect.DeepEqual(res, []string{"qwe", "qw", "es", "wqe"}) {
            b.Errorf("Mismatch")
        }
    }
 
}
 
func benchmarkFib(b *testing.B, n int) {
    for i := 0; i < b.N; i++ {
        Fib(n)
    }
}
 
func BenchmarkFib5(b *testing.B)  { benchmarkFib(b, 5) }
func BenchmarkFib10(b *testing.B) { benchmarkFib(b, 10) }
func BenchmarkFib15(b *testing.B) { benchmarkFib(b, 15) }
func BenchmarkFib20(b *testing.B) { benchmarkFib(b, 20) }

The code of the tested function is as follows:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//File name substr go
package main
 
import (
    "fmt"
    "strings"
)
 
func subStr(str, stre string) []string {
    index := strings.Index(str, stre)
    var theSub []string
 
    for index >= 0 {
        // Save the data in front of the separator first
        temp := str[:index]
        // Move string back
        str = str[index+1:]
        // Retrieve subscript
        index = strings.Index(str, stre)
        if temp != "" {
            theSub = append(theSub, temp)
        } else {
            continue
        }
    }
    theSub = append(theSub, str)
    return theSub[:]
}
 
// Fibonacci sequence
func Fib(n int) int {
    if n < 2 {
        return n
    }
    return Fib(n-1) + Fib(n-2)
}
 
func main() {
    fmt.Println(subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":"))
    fmt.Printf("%#v\n", subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":"))
    fmt.Println(123)
}

Put the above two files in the same directory and execute the test commandgo test
 

Test results obtained:

    goos: windows
    goarch: amd64
    cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
    BenchmarkSubStr-8   1213681       1012 ns/op      352 B/op  14 allocs/op
    PASS
    ok      _/ d_/ Go language learning notes / go language grammar section / go Language Advanced Grammar / 8 Unit test / benchmark 2.410s

2. Group test and sub test

  • The test of a function is not just a set of test cases, so we need to write test groups to test a function. The test is generally composed of set key value pairs, and each key corresponds to a set of test data
  • Individual group errors may occur during group testing, so a case can be tested separately by using subtest, which is the background of test group and subtest

The test functions are as follows:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main
 
import (
    "reflect"
    "testing"
)
 
type testS struct {
    str  string
    ste  string
    want []string
}
 
//Conduct group test and batch test. If there is any dissatisfaction, throw an exception
// func TestSubStr(t *testing.T) {
//     testMap := map[string]testS{
//         "case_1": {"123:eqwe:123", ":", []string{"123", "eqwe", "123"}},
//         "case_2": {"13:eqwe3:[email protected]", "3:", []string{"1", "eqwe", "[email protected]"}},
//         "case_4": {"123:[email protected]:[email protected]@3", "[email protected]", []string{"123:e", "we:[email protected]@3"}},
//         "case_5": {"123:eqwe:123", "2", []string{"1", "3:eqwe:1", "3"}},
//         "case_6": {"123:eqwe:123", "eqwe", []string{"123:", ":123"}},
//     }
//     for k, v := range testMap {
//         res := subStr(v.str, v.ste)
//         if !reflect.DeepEqual(res, v.want) {
//             t.Errorf("%v want:%#v got:%#v", k, v.want, res)
//         }
//     }
// }
 
// Sub test can be conducted for a sub sample
func TestSubStr(t *testing.T) {
    testMap := map[string]testS{
        "case_1": {"13:eqwe:123", ":", []string{"123", "eqwe", "123"}},
        "case_2": {"3:eqwe3:[email protected]", "3:", []string{"1", "eqwe", "[email protected]"}},
        "case_4": {"123:[email protected]:[email protected]@3", "[email protected]", []string{"123:e", "we:[email protected]@3"}},
        "case_5": {"23:eqwe:123", "2", []string{"1", "3:eqwe:1", "3"}},
        "case_6": {"123:eqwe:123", "eqwe", []string{"123:", ":123"}},
    }
    for k, v := range testMap {
        t.Run(k, func(t *testing.T) {
            res := subStr(v.str, v.ste)
            if !reflect.DeepEqual(res, v.want) {
                t.Errorf("want:%#v got:%#v", v.want, res)
            }
        })
 
    }
}

The functions to be tested are as follows:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main
 
import (
    "fmt"
    "strings"
)
 
func subStr(str, stre string) []string {
    index := strings.Index(str, stre)
    var theSub []string
 
    for index >= 0 {
        // Save the data in front of the separator first
        temp := str[:index]
        // Move string back
        str = str[index+len(stre):]
        // Retrieve subscript
        index = strings.Index(str, stre)
        if temp != "" {
            theSub = append(theSub, temp)
        } else {
            continue
        }
    }
    theSub = append(theSub, str)
    return theSub[:]
}
 
func main() {
    fmt.Println(subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":c"))
    fmt.Printf("%#v\n", subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":"))
    fmt.Println(123)
}

(1). Group test result analysis and command:

  • The group test command is still usedgo test

— FAIL: TestSubStr (0.00s)
    — FAIL: TestSubStr/case_1 (0.00s)
       subStr_test.go:46: want:[]string{“123”, “eqwe”, “123”} got:[]string{“13”, “eqwe”, “123”}        
    — FAIL: TestSubStr/case_2 (0.00s)
         subStr_test.go:46: want:[]string{“1”, “eqwe”, “[email protected]”} got:[]string{“eqwe”, “[email protected]”}
    — FAIL: TestSubStr/case_3 (0.00s)
         subStr_test.go:46: want:[]string{“[email protected]”, “@[email protected]”, “[email protected]”} got:[]string{“[email protected]”, “@[email protected]”, “[email protected]”}
    — FAIL: TestSubStr/case_5 (0.00s)
         subStr_test.go:46: want:[]string{“1”, “3:eqwe:1”, “3”} got:[]string{“3:eqwe:1”, “3”}
    FAIL
    exit status 1
    FAIL    _/ D_/ Go language learning notes / go language grammar section / go Language Advanced Grammar / 8 Unit test / group test and sub test 0.155s

(2). Sub test result analysis and command:

  • For example, test case separately_ 1. The command used isgo test -v -run=TestSubStr/case_1(the equal sign is followed by the directory after the test failure case fail of the above group)

=== RUN   TestSubStr
=== RUN   TestSubStr/case_1
    subStr_test.go:46: want:[]string{“123”, “eqwe”, “123”} got:[]string{“13”, “eqwe”, “123”}
— FAIL: TestSubStr (0.00s)
    — FAIL: TestSubStr/case_1 (0.00s)
FAIL
exit status 1
FAIL    _/ D_/ Go language learning notes / go language grammar section / go Language Advanced Grammar / 8 Unit test / group test and sub test 0.186s

3、 Pprof debugging tool

1. Transfer parameters to the main function

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(1)os.Args
package main1
 
import (
    "fmt"
    "os"
)
 
func main() {
    // os. Args can pass parameters when executing the function, but there is no way to parse - name = XXX
    if os.Args != nil {
        for index, temp := range os.Args {
            fmt.Println("Article", index+1, The first argument is:, temp)
        }
    }
    fmt.Println("hello")
}

(2)flag.Args

  • Relative to OS For args, flag Args is more convenient to use
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
 
import (
    "flag"
    "fmt"
    "time"
)
 
func main() {
    // The first parameter is the corresponding parameter, the second parameter is the default value, and the third parameter is prompt
    // Returns a pointer of the corresponding type
    // name := flag.String("name", "Tom", "Enter name")
    // sex := flag.Bool("sex", true, "Is it male?")
    // age := flag.Int("age", 10, "Age")
    // flag.Parse()
    // fmt.Println(*name, *sex, *age)
    var name string
    var age int
    var sex bool
    flag.StringVar(&name, "name", "Tom", "Enter name")
    flag.BoolVar(&sex, "sex", true, "Is it male?")
    flag.IntVar(&age, "age", 10, "Age")
    tim := flag.Duration("time", time.Hour, "Time")
    // Parse the input data. If you don't use this sentence, you can't get the value corresponding to attributes such as name, sex, age, etc
    flag.Parse()
    fmt.Println(name, sex, age, *tim)
    fmt.Println(flag.Args())  //Returns parameters other than the command line in a sliced manner
    fmt.Println(flag.NArg())  //Returns the number of parameters other than the command line
    fmt.Println(flag.NFlag()) //Returns the number of parameters using the command line
}

2. Pprof performance tuning

pprofThe debugging tool mainly focuses on the time efficiency of the test module. When debugging, only code segments that consume more time and space will be displayed

Files that generate debug code blocks:go run xx.exe -cpu....
Use go language tools to check the problems of code blocks:go tool pprof cpu.pprof

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main
 
import (
    "flag"
    "fmt"
    "os"
    "runtime/pprof"
    "time"
)
// A piece of problematic code
func logicCode() {
    var c chan int
    for {
        select {
        case v := <-c:
            fmt.Printf("recv from chan, value:%v\n", v)
        default:
 
        }
    }
}
 
func main() {
    var isCPUPprof bool
    var isMemPprof bool
    //Get received parameters
    flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
    flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
    flag.Parse()
    //Determine what test to do, then branch and save the information to the corresponding file.
    if isCPUPprof {
        file, err := os.Create("./cpu.pprof")
        if err != nil {
            fmt.Printf("create cpu pprof failed, err:%v\n", err)
            return
        }
        pprof.StartCPUProfile(file)
        defer pprof.StopCPUProfile()
    }
    for i := 0; i < 8; i++ {
        go logicCode()
    }
    time.Sleep(20 * time.Second)
    if isMemPprof {
        file, err := os.Create("./mem.pprof")
        if err != nil {
            fmt.Printf("create mem pprof failed, err:%v\n", err)
            return
        }
        pprof.WriteHeapProfile(file)
        file.Close()
    }
}

Summary:

Here, the commonly used test functions and sub tests are explained in detail, and the parameter tuning of pprof is only introduced. You can find some examples of pprof on the Internet according to your interest, and it is very convenient to carry out automatic testing.

This is the end of this article about the super detailed analysis of go language unit test. For more information about go language unit test, please search the previous articles of developeppaper or continue to browse the relevant articles below. I hope you will support developeppaper in the future!