###### tags: `GoLang`
# GoLang 05. 開發工具:
### Go 專案資料夾佈局:
https://github.com/golang-standards/project-layout
```bash
directory
├── /api #OpenAPI/Swagger 規範,JSON 模式(schema)文件...
├── /build #專案執行檔放置處,目錄內包含機器執行所需要的檔案
├── /cmd #如果專案編寫包含多個執行檔,將各自package main放置各目錄內
│ ├── authtest
│ │ └── main.go
│ ├── backend
│ │ └── main.go
│ └── client
│ └── main.go
├── /configs #設定檔集,如預設設定.不同OS環境設定...
├── /docs #專案文檔放置處
├── /deploy #容器化專案所需檔案放置處(選用)
│ ├── add_migration.sh
│ └── docker-compose.yml
├── /migrations/ #db特定操作(非標準方式)
│ ├── 20190721131113_extensions.down.sql
│ ├── migrations.go
│ └── README.md
│#vendor/internal/pkg 三者目錄可在go專案內子資料夾中出現
├── /vendor #Go專案外部依賴包或第三方包,可由go mod vendor產生
├── /internal #main之私用package
├── /pkg #main之公用package
│ ├── api/
│ │ ├── exitus.gen.go
│ │ └── gen.go
│ ├── auth/
│ │ ├── scopes.go
│ │ └── user.go
│ ├── conf/
│ │ ├── conf.go
│ │ └── conf_test.go
│ ├── db/
│ │ ├── db.go
│ │ ├── dbtesting.go
│ │ └── sqlhooks.go
│ ├── server/
│ │ └── server.go
│ └── store/
│ ├── comments.go
│ ├── comments_test.go
│ └── store.go
├── /scripts #build相關腳本放置處(選用)
├── /website #靜態資源檔案放置處
├── /assets #其他資源檔案放置處,如logos
├── Dockerfile
├── go.mod
├── go.sum
└── README.md
```
### Go 環境設置:
#### Windwos
```ini
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\.go]
@="Go.Code.Template"
[HKEY_CLASSES_ROOT\.go\ShellNew]
"FileName"="Template.go"
[HKEY_CLASSES_ROOT\Go.Code.Template]
@="Go Code Template"
```
### Go 單元測試(Unit Test)介紹:
>
> #### go test 工具說明 :
> Golang 官方工具包提供單元測試功能透過,``go test`` 進行單元測試:
>
> > 1. 單元測試檔名必須以 ``*_test.go`` 結尾命名,和被測試檔案必須在同一個包(package)中,此檔名內容僅會在 ``go test`` 下執行。
> > 2. 單元測試函式必須是 ``Test`` 或是 ``Benchmark`` 作為函式開頭名稱後面第一字必需大寫 ex: **TestExample** 、**BenchmarkExample** 。
> > 3. 單元測試函式輸入參數型別必須 ``*testing.T`` 、 ``*testing.B``
> >
>
> ``go test`` 工具附加命令參數設定值:
>
> > ``-c`` : 不運行測試,將go test編譯成為可執行檔案(二進位文件)。
> >
> > ``-i`` : 不運行測試,安裝測試包依賴的package。
> >
> > ``-v`` : 測試過程顯示列表所有函式(通過/不通過)。
> >
> > ``-short`` : 縮短運行時間較長的測試項目。
> >
> > ``-args "-TT"`` : 測試時置入命令參數 **-TT** (詳細參考flag.Args)
> >
> > ``-timeout 1h`` : 如果測試用例運行時間超過 **1小時**,則拋出panic。
> >
> > ``-run=funcname`` : 僅測試函式包含名稱 **funcname** 。(預設值 ``.``,表示全部測試)
> >
> > ``-bench=funcname`` : 僅效能測試函式包含名稱 **funcname** 。(預設值 ``.``,表示全測試)
> >
> > ``-benchmem`` : 設置效能測試的時顯示記憶體使用資訊。
> >
> > ``-benchtime 10s`` : 設置效能測試運行的時間 **10秒** (預設值**1秒**)
> >
> > ``-parallel 4`` : 設定效能測試並行最大CPU核心數為 **4** (預設值GOMAXPROCS)
> >
> > ``-cpu 1,2,3,4`` : 效能測試會依序由 **1~4** CPU核心數測試。(預設值為GOMAXPROCS)
> >
> > ``-cpuprofile cpu.out`` : 將測試過程CPU使用量紀錄儲存至 **cpu.out**
> >
> > ``-memprofile mem.out`` : 將測試過程記憶體使用量紀錄儲存至 **mem.out**
> >
> > ``-blockprofile block.out`` : 將測試過程中goroutine阻塞分析紀錄儲存至 **block.out**
> >
> > ``-blockprofilerate 2`` : 設置goroutine阻塞時候紀錄間隔時間為 **2納秒** (預設值**1納秒**)
> >
> #### 單元測試關鍵點 :
>
> 測試資料構造時要考慮這樣幾個方面:
> >**正常輸入**: 驗證函式的正常邏輯是否通過
> >**邊界輸入**: 驗證在極端情況下的輸入,函式是否在有相應的容錯處理
> >**非法輸入**: 對於一些非正常輸入,看函式是否引起函式的奔潰和資料洩露等問題
> >**白盒覆蓋**: 覆蓋到函式的所有程式碼,語句覆蓋、條件覆蓋、分支覆蓋、分支/條件覆蓋、條件組合覆蓋。
>
> 編寫原則與成本,效率權衡 :
>
> > 1. 優先編寫核心元件和邏輯模組的測試用例。
> > 2. 邏輯類似的元件如果存在多個,優先編寫其中一種邏輯元件的測試用例。
> > 3. 發現Bug時一定先編寫測試用例進行Debug(保持更新測試用例)。
> > 4. 測試使用者應該獨立一個檔案對應一個,不同的測試用例之間不要互相依賴。
> >
> 原始資料出處 : https://www.itread01.com/hkpqhkxx.html
### Go 單元測試範例 - 函式輸入與期望結果對比:
> ```go=
> //Basic_Unit_Testing1\Basic_Unit_Testing_Example1.go
> package Basic_Unit_Testing_Example1
> func fc_AddInt(vi_inputA, vi_inputB int) int {
> return vi_inputA + vi_inputB
> }
> ```
>
> ```go=
> //Basic_Unit_Testing1\Basic_Unit_Testing_Example1_test.go
> package Basic_Unit_Testing_Example1
>
> import (
> "fmt"
> "testing"
> )
>
> func Test_fc_AddInt(testT *testing.T) {
>
> var vs_theTestPanic string
> defer func() {
> if err_recover := recover(); err_recover != nil {
> testT.Fatalf("測試過程發生panic,本測項中止 -「%v」(%v)", vs_theTestPanic, err_recover)
> }
> }()
>
> var stsl_Testers = []struct {
> add1 int
> add2 int
> want int
> }{
> {1, 1, 2},
> {2, 0, 2},
> {0, 2, 2},
> {9223372036854775807, -1, 9223372036854775806},
> {9223372036854775806, 1, 9223372036854775807},
> {9223372036854775807, 9223372036854775807, 0}, //overflows
> {-1, -1, -2},
> }
>
> for vi_TestIndex, st_TestObject := range stsl_Testers {
> vs_theTestPanic = fmt.Sprintf("stsl_Testers[%v] %v", vi_TestIndex, st_TestObject)
> theTestResult := fc_AddInt(st_TestObject.add1, st_TestObject.add2)
> if theTestResult == st_TestObject.want {
> testT.Logf("項目測試正確 %v+%v=%v(%v)", st_TestObject.add1, st_TestObject.add2, st_TestObject.want, theTestResult)
> } else {
> testT.Errorf("項目測試[錯誤] %v+%v=%v(錯誤的結果:%v)", st_TestObject.add1, st_TestObject.add2, st_TestObject.want, theTestResult)
> }
> }
> }
> ```
> ```sass=
> d:\單元測試\Basic_Unit_Testing1>go test -v
> === RUN Test_fc_AddInt
> --- FAIL: Test_fc_AddInt (0.00s)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 1+1=2(2)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 2+0=2(2)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 0+2=2(2)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 9223372036854775807+-1=9223372036854775806(9223372036854775806)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 9223372036854775806+1=9223372036854775807(9223372036854775807)
> Basic_Unit_Testing_Example1_test.go:37: 項目測試[錯誤] 9223372036854775807+9223372036854775807=0(錯誤的結果:-2)
> Basic_Unit_Testing_Example1_test.go:35: 項目測試正確 -1+-1=-2(-2)
> FAIL
> exit status 1
> FAIL Lesson4/單元測試/Basic_Unit_Testing1 0.026s
> ```
### Go 單元測試範例 - 函式輸入與錯誤回報:
> ```go=
> //Basic_Unit_Testing2\Basic_Unit_Testing_Example2.go
> package Basic_Unit_Testing_Example2
> import (
> "errors"
> )
>
> func fc_DivInt(vi_inputA, vi_inputB int) int {
> return vi_inputA / vi_inputB
> }
>
> func fc_DivIntMod(vi_inputA, vi_inputB int) (int, error) {
> if vi_inputB == 0 {
> return 0, errors.New("除數不得為0")
> }
> return vi_inputA / vi_inputB, nil
> }
>
> ```
>
> ```go=
> //Basic_Unit_Testing2\Basic_Unit_Testing_Example2_test.go
> package Basic_Unit_Testing_Example2
>
> import (
> "errors"
> "fmt"
> "testing"
> )
>
> func Test_fc_DivIntMod(testT *testing.T) {
>
> var vs_theTestPanic string
> defer func() {
> if err_recover := recover(); err_recover != nil {
> testT.Fatalf("測試過程發生panic,本測項中止 -「%v」(%v)", vs_theTestPanic, err_recover)
> }
> }()
>
> type ty_TestIndex struct {
> dividend int
> divisor int
> want1 int
> want2 error
> }
>
> var stsl_Testers = []ty_TestIndex{
> {1, 1, 1, nil},
> {10, 2, 5, nil},
> {0, 2, 0, nil},
> {9223372036854775807, 1, 9223372036854775807, nil},
> {9223372036854775806, 3, 3074457345618258602, nil},
> {9223372036854775807, 4611686018427387903, 2, nil},
> {9223372036854775807, 0, 0, errors.New("除數不得為0")}, //除零預期錯誤
> {-1, 1, -1, nil},
> }
>
> for vi_TestIndex, st_TestObject := range stsl_Testers {
> vs_theTestPanic = fmt.Sprintf("stsl_Testers[%v] %v", vi_TestIndex, st_TestObject)
> theTestResult1, theTestResult2 := fc_DivIntMod(st_TestObject.dividend, st_TestObject.divisor)
>
> if theTestResult2 == nil {
> theTestResult2 = errors.New("nil")
> }
> if st_TestObject.want2 == nil {
> st_TestObject.want2 = errors.New("nil")
> }
>
> if theTestResult1 == st_TestObject.want1 && theTestResult2.Error() == st_TestObject.want2.Error() {
> testT.Logf("項目測試正確 %v/%v=%v,%v(%v,%v)", st_TestObject.dividend, st_TestObject.divisor, st_TestObject.want1, st_TestObject.want2, theTestResult1, theTestResult2)
> } else {
> testT.Errorf("項目測試[錯誤] %v/%v=%v,%v(錯誤的結果:%v,%v)", st_TestObject.dividend, st_TestObject.divisor, st_TestObject.want1, st_TestObject.want2, theTestResult1, theTestResult2)
> }
> }
>
> }
> ```
>
> ```sass=
> d:\單元測試\Basic_Unit_Testing2>go test -v
> === RUN Test_fc_DivIntMod
> --- PASS: Test_fc_DivIntMod (0.00s)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 1/1=1,nil(1,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 10/2=5,nil(5,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 0/2=0,nil(0,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 9223372036854775807/1=9223372036854775807,nil(9223372036854775807,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 9223372036854775806/3=3074457345618258602,nil(3074457345618258602,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 9223372036854775807/4611686018427387903=2,nil(2,nil)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 9223372036854775807/0=0,除數不得為0(0,除數不得為0)
> Basic_Unit_Testing_Example2_test.go:48: 項目測試正確 -1/1=-1,nil(-1,nil)
> PASS
> ok Lesson4/單元測試/Basic_Unit_Testing2 0.025s
> ```
### Go 單元測試範例 - 雙函式結果對比(隨機輸入):
> ```go=
> //Basic_Unit_Testing3\Basic_Unit_Testing_Example3.go
> package Basic_Unit_Testing_Example3
>
> func fc_SumA(via_Input ...int) int {
> var vi_sum int
> for i := 0; i < len(via_Input); i++ {
> vi_sum += via_Input[i]
> }
> return vi_sum
> }
>
> func fc_SumB(vi_sum int, via_Input ...int) int {
> for i := 0; i < len(via_Input); i++ {
> vi_sum += via_Input[i]
> }
> return vi_sum
> }
> ```
>
> ```go=
> //Basic_Unit_Testing3\Basic_Unit_Testing_Example_test3.go
> package Basic_Unit_Testing_Example3
>
> import (
> "math/rand"
> "testing"
> "time"
> )
>
>
> func Test_fc_SumAnB(testT *testing.T) {
>
> var vs_theTestPanic string
> defer func() {
> if err_recover := recover(); err_recover != nil {
> testT.Fatalf("測試過程發生panic,本測項中止 -「%v」(%v)", vs_theTestPanic, err_recover)
> }
> }()
>
> theRandSeed := time.Now().UTC().UnixNano()
> rand.Seed(theRandSeed)
> var vi_RandInt int
> var vi_Output_fc_SumA int
> var vi_Output_fc_SumB int
>
> for index := 0; index < 10; index++ {
> vi_RandInt = rand.Int()
> vi_Output_fc_SumA = fc_SumA(vi_RandInt)
> vi_Output_fc_SumB = fc_SumB(vi_RandInt)
> if fc_SumA(vi_RandInt) == fc_SumB(vi_RandInt) {
> testT.Logf("項目測試正確 %v=%v (亂數種子:%d,亂數int:%v)", vi_Output_fc_SumA, vi_Output_fc_SumB, theRandSeed, vi_RandInt)
> } else {
> testT.Errorf("項目測試[錯誤] %v=%v (亂數種子:%d,亂數int:%v)", vi_Output_fc_SumA, vi_Output_fc_SumB, theRandSeed, vi_RandInt)
> }
> }
> }
>
> ```
> ```sass=
> d:\單元測試\Basic_Unit_Testing3>go test -v
> === RUN Test_fc_SumAnB
> --- PASS: Test_fc_SumAnB (0.00s)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 128637770004810965=128637770004810965 (亂數種子:1570086382169605200,亂數int:128637770004810965)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 2710904496263871649=2710904496263871649 (亂數種子:1570086382169605200,亂數int:2710904496263871649)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 7459572758933604767=7459572758933604767 (亂數種子:1570086382169605200,亂數int:7459572758933604767)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 7058483080362729371=7058483080362729371 (亂數種子:1570086382169605200,亂數int:7058483080362729371)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 7049057841437937710=7049057841437937710 (亂數種子:1570086382169605200,亂數int:7049057841437937710)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 8952472848806917481=8952472848806917481 (亂數種子:1570086382169605200,亂數int:8952472848806917481)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 7580769296778865075=7580769296778865075 (亂數種子:1570086382169605200,亂數int:7580769296778865075)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 5973232751947046394=5973232751947046394 (亂數種子:1570086382169605200,亂數int:5973232751947046394)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 2797291425107336826=2797291425107336826 (亂數種子:1570086382169605200,亂數int:2797291425107336826)
> Basic_Unit_Testing_Example3_test.go:30: 項目測試正確 1338551253019334488=1338551253019334488 (亂數種子:1570086382169605200,亂數int:1338551253019334488)
> PASS
> ok Lesson4/單元測試/Basic_Unit_Testing3 0.028s
> ```
### Go 效能測試範例 - (go test -bench=):
>
> ```go=
> //d:\效能測試\Basic_Benchmark.go
> package Basic_Benchmark
> import "fmt"
> func fc_SprintInt(vi_input int) string {
> return fmt.Sprintf("%d", vi_input)
> }
>
> ```
>
> ```go=
> //d:\效能測試\Basic_Benchmark_test.go
> package Basic_Benchmark
> import "testing"
> func Benchmark_fc_SprintInt(benchB *testing.B) {
> benchB.ResetTimer()
> for i := 0; i < benchB.N; i++ {
> fc_SprintInt(99999)
> }
> }
>
> ```
> go test -bench=. -cpu 1,2,3,4 -cpuprofile cpu.out -memprofile mem.out -blockprofile block.out
>
> ```sass=
> d:\效能測試>go test -bench=. -cpu 1,2,3,4 -cpuprofile cpu.out -memprofile mem.out -blockprofile block.out
> go test: missing argument for flag blockprofile
> run "go help test" or "go help testflag" for more information
>
> d:\效能測試>go test -bench=. -cpu 1,2,3,4 -cpuprofile cpu.out -memprofile mem.out -blockprofile block.out
> goos: windows
> goarch: amd64
> pkg: Lesson4/效能測試
> Benchmark_fc_SprintInt 10000000 194 ns/op
> Benchmark_fc_SprintInt-2 10000000 163 ns/op
> Benchmark_fc_SprintInt-3 10000000 159 ns/op
> Benchmark_fc_SprintInt-4 10000000 139 ns/op
> PASS
> ok Lesson4/效能測試 7.583s
>
> d:\效能測試>go tool pprof -text -nodecount=10 cpu.out
> Type: cpu
> Time: Sep 3, 2019 at 5:35pm (CST)
> Duration: 7.45s, Total samples = 7300ms (97.99%)
> Showing nodes accounting for 4490ms, 61.51% of 7300ms total
> Dropped 46 nodes (cum <= 36.50ms)
> Showing top 10 nodes out of 52
> flat flat% sum% cum cum%
> 830ms 11.37% 11.37% 1650ms 22.60% runtime.mallocgc
> 800ms 10.96% 22.33% 1470ms 20.14% fmt.(*fmt).fmtInteger
> 580ms 7.95% 30.27% 2600ms 35.62% fmt.(*pp).doPrintf
> 380ms 5.21% 35.48% 2020ms 27.67% fmt.(*pp).printArg
> 350ms 4.79% 40.27% 640ms 8.77% sync.(*Pool).Get
> 350ms 4.79% 45.07% 630ms 8.63% sync.(*Pool).Put
> 330ms 4.52% 49.59% 1430ms 19.59% runtime.slicebytetostring
> 290ms 3.97% 53.56% 670ms 9.18% fmt.(*fmt).pad
> 290ms 3.97% 57.53% 6140ms 84.11% fmt.Sprintf
> 290ms 3.97% 61.51% 290ms 3.97% runtime.memmove
>
> d:\效能測試>go tool pprof -text -nodecount=10 mem.out
> Type: alloc_space
> Time: Sep 3, 2019 at 5:35pm (CST)
> Showing nodes accounting for 637.51MB, 99.50% of 640.68MB total
> Dropped 17 nodes (cum <= 3.20MB)
> flat flat% sum% cum cum%
> 371.51MB 57.99% 57.99% 372.01MB 58.06% fmt.Sprintf
> 266MB 41.52% 99.50% 638.01MB 99.58% Lesson4/%e6%95%88%e8%83%bd%e6%b8%ac%e8%a9%a6.fc_SprintInt
> 0 0% 99.50% 638.01MB 99.58% Lesson4/%e6%95%88%e8%83%bd%e6%b8%ac%e8%a9%a6.Benchmark_fc_SprintInt
> 0 0% 99.50% 638.01MB 99.58% testing.(*B).launch
> 0 0% 99.50% 638.01MB 99.58% testing.(*B).runN
>
> d:\效能測試>go tool pprof -text -nodecount=10 block.out
> Type: delay
> Time: Sep 3, 2019 at 5:35pm (CST)
> Showing nodes accounting for 7466.18ms, 100% of 7466.19ms total
> Dropped 5 nodes (cum <= 37.33ms)
> Showing top 10 nodes out of 17
> flat flat% sum% cum cum%
> 7466.18ms 100% 100% 7466.18ms 100% runtime.chanrecv1
> 0 0% 100% 7466.19ms 100% main.main
> 0 0% 100% 7466.19ms 100% runtime.main
> 0 0% 100% 153.33ms 2.05% runtime/pprof.StopCPUProfile
> 0 0% 100% 153.33ms 2.05% sync.(*Once).Do
> 0 0% 100% 7312.85ms 97.95% testing.(*B).Run
> 0 0% 100% 7311.72ms 97.93% testing.(*B).doBench
> 0 0% 100% 7312.62ms 97.94% testing.(*B).run
> 0 0% 100% 7312.85ms 97.95% testing.(*B).runN
> 0 0% 100% 7466.19ms 100% testing.(*M).Run
>
> ```
### Go 涵蓋率測試範例 - (go tool cover):
> ```go=
> // 涵蓋率測試/Cover_Testing_Example.go
> package Cover_Testing_Example
> func fc_AddInt(vi_inputA, vi_inputB int) int {
> return vi_inputA + vi_inputB
> }
>
> func fc_SubInt(vi_inputA, vi_inputB int) int {
> return vi_inputA - vi_inputB
> }
>
> func fc_SumA(via_Input ...int) int {
> var vi_sum int
> for i := 0; i < len(via_Input); i++ {
> vi_sum += via_Input[i]
> }
> return vi_sum
> }
>
> func fc_SumB(vi_sum int, via_Input ...int) int {
> for i := 0; i < len(via_Input); i++ {
> vi_sum += via_Input[i]
> }
> return vi_sum
> }
> ```
>
> ```go=
> // 涵蓋率測試/Cover_Testing_Example_test.go
> package Cover_Testing_Example
> import (
> "fmt"
> "math/rand"
> "testing"
> "time"
> )
>
> func Test_fc_AddInt(testT *testing.T) {
>
> var vs_theTestPanic string
> defer func() {
> if err_recover := recover(); err_recover != nil {
> testT.Fatalf("測試過程發生panic,本測項中止 -「%v」(%v)", vs_theTestPanic, err_recover)
> }
> }()
>
> var stsl_Testers = []struct {
> add1 int
> add2 int
> want int
> }{
> {1, 1, 2},
> {2, 0, 2},
> {0, 2, 2},
> {9223372036854775807, -1, 9223372036854775806},
> {9223372036854775806, 1, 9223372036854775807},
> {9223372036854775807, 9223372036854775807, 0}, //overflows
> {-1, -1, -2},
> }
>
> for vi_TestIndex, st_TestObject := range stsl_Testers {
> vs_theTestPanic = fmt.Sprintf("stsl_Testers[%v] %v", vi_TestIndex, st_TestObject)
> theTestResult := fc_AddInt(st_TestObject.add1, st_TestObject.add2)
> if theTestResult == st_TestObject.want {
> testT.Logf("項目測試正確 %v+%v=%v(%v)", st_TestObject.add1, st_TestObject.add2, st_TestObject.want, theTestResult)
> } else {
> testT.Errorf("項目測試[錯誤] %v+%v=%v(錯誤的結果:%v)", st_TestObject.add1, st_TestObject.add2, st_TestObject.want, theTestResult)
> }
> }
> }
>
> func Test_fc_SumAnB(testT *testing.T) {
>
> var vs_theTestPanic string
> defer func() {
> if err_recover := recover(); err_recover != nil {
> testT.Fatalf("測試過程發生panic,本測項中止 -「%v」(%v)", vs_theTestPanic, err_recover)
> }
> }()
>
> theRandSeed := time.Now().UTC().UnixNano()
> rand.Seed(theRandSeed)
> var vi_RandInt int
> var vi_Output_fc_SumA int
> var vi_Output_fc_SumB int
>
> for index := 0; index < 10; index++ {
> vi_RandInt = rand.Int()
> vi_Output_fc_SumA = fc_SumA(vi_RandInt)
> vi_Output_fc_SumB = fc_SumB(vi_RandInt)
> if fc_SumA(vi_RandInt) == fc_SumB(vi_RandInt) {
> testT.Logf("項目測試正確 %v=%v (亂數種子:%d,亂數int:%v)", vi_Output_fc_SumA, vi_Output_fc_SumB, theRandSeed, vi_RandInt)
> } else {
> testT.Errorf("項目測試[錯誤] %v=%v (亂數種子:%d,亂數int:%v)", vi_Output_fc_SumA, vi_Output_fc_SumB, theRandSeed, vi_RandInt)
> }
> }
> }
>
> ```
>
> ```sass=
> PS D:\涵蓋率測試> go test -v -cover -coverprofile cover.out
> === RUN Test_fc_AddInt
> --- FAIL: Test_fc_AddInt (0.00s)
> Cover_Testing_Example_test.go:37: 項目測試正確 1+1=2(2)
> Cover_Testing_Example_test.go:37: 項目測試正確 2+0=2(2)
> Cover_Testing_Example_test.go:37: 項目測試正確 0+2=2(2)
> Cover_Testing_Example_test.go:37: 項目測試正確 9223372036854775807+-1=9223372036854775806(9223372036854775806)
> Cover_Testing_Example_test.go:37: 項目測試正確 9223372036854775806+1=9223372036854775807(9223372036854775807)
> Cover_Testing_Example_test.go:39: 項目測試[錯誤] 9223372036854775807+9223372036854775807=0(錯誤的結果:-2)
> Cover_Testing_Example_test.go:37: 項目測試正確 -1+-1=-2(-2)
> === RUN Test_fc_SumAnB
> --- PASS: Test_fc_SumAnB (0.00s)
> Cover_Testing_Example_test.go:64: 項目測試正確 1054791156209780183=1054791156209780183 (亂數種子:1570164062516555300,亂數int:1054791156209780183)
> Cover_Testing_Example_test.go:64: 項目測試正確 1572036677946546427=1572036677946546427 (亂數種子:1570164062516555300,亂數int:1572036677946546427)
> Cover_Testing_Example_test.go:64: 項目測試正確 4043804078525964286=4043804078525964286 (亂數種子:1570164062516555300,亂數int:4043804078525964286)
> Cover_Testing_Example_test.go:64: 項目測試正確 4490900911252265608=4490900911252265608 (亂數種子:1570164062516555300,亂數int:4490900911252265608)
> Cover_Testing_Example_test.go:64: 項目測試正確 9189757511242968573=9189757511242968573 (亂數種子:1570164062516555300,亂數int:9189757511242968573)
> Cover_Testing_Example_test.go:64: 項目測試正確 8466299651324370872=8466299651324370872 (亂數種子:1570164062516555300,亂數int:8466299651324370872)
> Cover_Testing_Example_test.go:64: 項目測試正確 600841189896519269=600841189896519269 (亂數種子:1570164062516555300,亂數int:600841189896519269)
> Cover_Testing_Example_test.go:64: 項目測試正確 8783876916636026197=8783876916636026197 (亂數種子:1570164062516555300,亂數int:8783876916636026197)
> Cover_Testing_Example_test.go:64: 項目測試正確 4035231185535482081=4035231185535482081 (亂數種子:1570164062516555300,亂數int:4035231185535482081)
> Cover_Testing_Example_test.go:64: 項目測試正確 4089254982128445097=4089254982128445097 (亂數種子:1570164062516555300,亂數int:4089254982128445097)
> FAIL
> coverage: 77.8% of statements
> exit status 1
> FAIL Lesson4/涵蓋率測試 0.029s
> ```
> **go tool cover** 工具指令獲得到測試涵蓋率 **77.8%** ,可藉由下方指令分析測試過程中涵蓋的程式碼 **Cover_Testing_Example.go** :
>
> ```sass=
> PS D:\涵蓋率測試> go tool cover -html cover.out
> ```
> 
> * 紅色部分表示測試未涵蓋到的程式碼
---