iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 24
1
Software Development

學習Go系列 第 24

Go day 24 (testing)

  • 分享至 

  • xImage
  •  

testing

在 go 要寫測試程式只要在程式名稱後面加上 _test.
例如程式名稱叫 example.go 只要再加上一隻 example_test.go.
目錄結構如下

goHello
 -src
  -practice
   -test
    example.go
    example_test.go

example.go

在 example.go 裡,提供了 Add 與 IsFindName 兩個方法讓外部呼叫.
Add 就是做加法,IsFindName 就是給個名字,可以幫你確認是否有這個 Name 在 names 這 Array 裡.

package test

func Add(x int, y int) int {
	return x + y
}

func IsFindName(findName string, names []string) bool {
	for _, n := range names {
		if n == findName {
			return true
		}
	}
	return false
}

example_test.go

測試程式除了檔名後面要加上 _test,裡面的測試 function 命名要以 Test 開頭在加上要測試的 function Name.
那因為 1 + 2 會等於 3,所以就寫說如果答案是 3 就印 success,否則就印 fail.

package test

import "testing"

func TestAdd(t *testing.T) {
	n := Add(1, 2)
	if n == 3 {
		t.Log("success")
	} else {
		t.Error("fail")
	}
}
func TestIsFindName(t *testing.T) {
	if isSuccess := IsFindName("Daniel", []string{"Andy", "Jack", "Daniel", "Sam"}); isSuccess {
		t.Log("success")
	} else {
		t.Error("fail")
	}
}

go test

寫好測試程式後,就下測試指令如下.-v 是顯示詳細測試結果,-cover=true 代表加上測試涵蓋率.

> go test -v -cover=true example_test.go example.

=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
    example_test.go:8: success
=== RUN   TestIsFindName
--- PASS: TestIsFindName (0.00s)
    example_test.go:15: success
PASS
coverage: 80.0% of statements
ok      command-line-arguments  (cached)        coverage: 80.0% of statements

執行完後會發現測試涵蓋率只有 80.0%,代表說 funtcion 可能有些地方沒有測到.
因為 Add 這 function 裡就只有 return x + y,所以應該是都測了.
所以應該是 IsFindName 這 function 有些地方沒測到,那因為測試案例裡,
目前只有測找得到 name 的結果,但找不到的沒測,也就是 return false 那邊可能沒測試到.
所以在 example_test.go 裡再補上針對 IsFindName 找不到 name 的測試(TestIsNotFindNames).

package test

import "testing"

func TestAdd(t *testing.T) {
	n := Add(1, 2)
	if n == 3 {
		t.Log("success")
	} else {
		t.Error("fail")
	}
}
func TestIsFindName(t *testing.T) {
	if isSuccess := IsFindName("Daniel", []string{"Andy", "Jack", "Daniel", "Sam"}); isSuccess {
		t.Log("success")
	} else {
		t.Error("fail")
	}
}
func TestIsNotFindNames(t *testing.T) {
	if isSuccess := IsFindName("Lucy", []string{"Andy", "Jack", "Daniel", "Sam"}); isSuccess {
		t.Error("fail")
	} else {
		t.Log("success")
	}
}

這時候在跑 go test 就會發現測試涵蓋率就會是 100% 了.

go test -v -cover=true example_test.go example.go
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
    example_test.go:8: success
=== RUN   TestIsFindName
--- PASS: TestIsFindName (0.00s)
    example_test.go:15: success
=== RUN   TestIsNotFindNames
--- PASS: TestIsNotFindNames (0.00s)
    example_test.go:25: success
PASS
coverage: 100.0% of statements
ok      command-line-arguments  0.005s  coverage: 100.0% of statements

gotests

可以使用 gotests 套件 幫忙產生測試程式.

下載安裝

> go get -u github.com/cweill/gotests/...

下指令幫忙產生 example_test.go 這隻測試程式

> gotests -all -w example.go example_test.go
Generated TestAdd
Generated TestIsFindName
No tests generated for example_test.go

產生出來的 example_test.go,只剩下參數的部分要自己補上.

package test

import "testing"

func TestAdd(t *testing.T) {
	type args struct {
		x int
		y int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Add(tt.args.x, tt.args.y); got != tt.want {
				t.Errorf("Add() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestIsFindName(t *testing.T) {
	type args struct {
		findName string
		names    []string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := IsFindName(tt.args.findName, tt.args.names); got != tt.want {
				t.Errorf("IsFindName() = %v, want %v", got, tt.want)
			}
		})
	}
}

接著只要在 TODO 補上要測試的參數即可,name 就是定個名稱,args 就是 input 的參數,want 就是想要的結果.

package test

import "testing"

func TestAdd(t *testing.T) {
	type args struct {
		x int
		y int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		// TODO: Add test cases.
		{
			name: "TestAddSuccess",
			args: args{
				x: 1,
				y: 2,
			},
			want: 3,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Add(tt.args.x, tt.args.y); got != tt.want {
				t.Errorf("Add() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestIsFindName(t *testing.T) {
	type args struct {
		findName string
		names    []string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		// TODO: Add test cases.
		{
			name: "TestIsFindNameSuccess",
			args: args{
				findName: "Daniel",
				names:    []string{"Andy", "Jack", "Daniel", "Sam"},
			},
			want: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := IsFindName(tt.args.findName, tt.args.names); got != tt.want {
				t.Errorf("IsFindName() = %v, want %v", got, tt.want)
			}
		})
	}
}

執行測試

go test -v -cover=true example_test.go example.go
=== RUN   TestAdd
=== RUN   TestAdd/TestAddSuccess
--- PASS: TestAdd (0.00s)
    --- PASS: TestAdd/TestAddSuccess (0.00s)
=== RUN   TestIsFindName
=== RUN   TestIsFindName/TestIsFindNameSuccess
--- PASS: TestIsFindName (0.00s)
    --- PASS: TestIsFindName/TestIsFindNameSuccess (0.00s)
PASS
coverage: 80.0% of statements
ok      command-line-arguments  (cached)        coverage: 80.0% of statements

上一篇
Go day 23 (io)
下一篇
Go day 25 (json)
系列文
學習Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言