Go language study notes 8 - testing and performance tuning

Go language study notes 8 - testing and performance tuning

Debugging Sucks! Testing Rocks!

traditional test

insert image description here

  • Test logic mixed with test data
  • The error message is not clear
  • Once a data error test all ends

form-driven testing

insert image description here

  • Separate test data and test logic
  • clear error message
  • can partially fail
  • The syntax of go language makes it easier for us to practice table-driven testing

func calcTriangle(a, b int) int {
    
    
	var c int
	c = int(math.Sqrt(float64(a*a + b*b)))
	return c
}

func TestTriangle(t *testing.T) {
    
    
	tests := []struct{
    
     a, b, c int }{
    
    
		{
    
    3, 4, 5},
		{
    
    5, 12, 13},
		{
    
    8, 15, 17},
		{
    
    12, 35, 37},
		{
    
    30000, 40000, 50000},
	}

	for _, tt := range tests {
    
    
		if actual := calcTriangle(tt.a, tt.b); actual != tt.c {
    
    
			t.Errorf("calcTriangle(%d,%d);"+
				"got %d;expected %d",
				tt.a, tt.b, actual, tt.c)
		}
	}
}

code coverage

Check the code coverage of the test code.
Green is covered, red is not covered
insert image description here
insert image description here

Performance Testing


func BenchmarkSubstr(b *testing.B) {
    
    
	aa := 30000
	bb := 40000
	cc := 50000

	for i := 0; i < b.N; i++ {
    
    
		actual := calcTriangle(aa, bb)
		if actual != cc {
    
    
			b.Errorf("calcTriangle(%d,%d);"+
				"got %d;expected %d",
				aa, bb, actual, cc)
		}
	}
}

result:insert image description here

pprof performance tuning

Command line command:

  1. go test -bench . -cpuprofile cpu.out Get cpu performance log file cpu.out
  2. go tool pprof cpu.out View log file
  3. For web visualization log files, Graphviz needs to be installed first, and the link can be downloaded and installed directly below.
    Graphviz

Visualize the result:

insert image description here

How to optimize map

Space for time
a:=make([]int,0xffff)
Assuming that the maximum Chinese character is 0xFFFF, here an array of 0xFFFF size can be used to store all characters
: a['e']=1 (essential: a[0x65]=1); a['class']=1 (Essential: a[0x8BFE]=1)

Performance Tuning Steps

  1. -cpuprofile: get performance data
  2. go tool pprof: View performance data
  3. Where is the analysis slow
  4. optimize code

http test

two methods

  • By using fake Request/Response
  • through the server

The tested functions refer to the server unified error handling in the previous note 7


func errPanic(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	panic(123)
}

type testingUserError string

func (e testingUserError) Error() string {
    
    
	return e.Message()
}
func (e testingUserError) Message() string {
    
    
	return string(e)
}

func errUserError(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	return testingUserError("user error")
}

func errNotFound(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	return os.ErrNotExist
}
func errNotPermission(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	return os.ErrPermission
}
func errUnknown(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	return errors.New("unknown error")
}
func noError(writer http.ResponseWriter,
	request *http.Request) error {
    
    
	fmt.Fprintln(writer, "no error")
	return nil
}
var tests = []struct {
    
    
	h       appHandler
	code    int
	message string
}{
    
    
	{
    
    errPanic, 500, "Internal Server Error"},
	{
    
    errUserError, 400, "user error"},
	{
    
    errNotFound, 404, "Not Found"},
	{
    
    errNotPermission, 403, "Forbidden"},
	{
    
    errUnknown, 500, "Internal Server Error"},
	{
    
    noError, 200, "no error"},
}

//用假的request,response,速度快
func TestErrWrapper(t *testing.T) {
    
    
	for _, tt := range tests {
    
    
		f := errWrapper(tt.h)
		response := httptest.NewRecorder()
		request := httptest.NewRequest(
			http.MethodGet, "http://www.imooc.com", nil)
		f(response, request)
		verifyResponse(response.Result(), tt.code, tt.message, t)
	}
}

//真正起一个server,测试力度更大
func TestErrWrapperInServer(t *testing.T) {
    
    
	for _, tt := range tests {
    
    
		f := errWrapper(tt.h)
		server := httptest.NewServer(http.HandlerFunc(f))
		resp, _ := http.Get(server.URL)
		verifyResponse(resp, tt.code, tt.message, t)
	}
}

func verifyResponse(resp *http.Response, expectedCode int, expectMsg string, t *testing.T) {
    
    
	b, _ := ioutil.ReadAll(resp.Body)
	body := strings.Trim(string(b), "\n")
	if resp.StatusCode != expectedCode || body != expectMsg {
    
    
		t.Errorf("expected(%d,%s);"+
			"got(%d,%s)",
			expectedCode, expectMsg,
			resp.StatusCode, body)
	}
}

Generate documentation

Write documentation with comments
Add Example to tests
Use go doc/godoc to view/generate documentation

godoc -http :6060Generate documentation, access via http://localhost:6060/pkg/

Notes


// An FIFO queue.
type Queue []int

// Pushes the element into the queue.
//  e.g. q.Push(123)
func (q *Queue) Push(v int) {
    
    
	*q = append(*q, v)
}

// Pops element from head.
func (q *Queue) Pop() int {
    
    
	head := (*q)[0]
	*q = (*q)[1:]
	return head
}

// Returns if the queue is empty or not.
func (q *Queue) IsEmpty() bool {
    
    
	return len(*q)==0
}

Sample code:
can also be used as a test

func ExampleQueue_Pop() {
    
    
   q := Queue{
    
    1}
   q.Push(2)
   q.Push(3)
   
   fmt.Println(q.Pop())
   fmt.Println(q.Pop())
   fmt.Println(q.IsEmpty())
   fmt.Println(q.Pop())
   fmt.Println(q.IsEmpty())

   // Output:
   // 1
   // 2
   // false
   // 3
   // true
}

Generate documentation:
insert image description here

Guess you like

Origin blog.csdn.net/shn111/article/details/122677040