欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程

 更新時(shí)間:2022年07月22日 09:41:05   作者:darjun  
這篇文章主要為大家介紹了Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

簡(jiǎn)介

testing是 Go 語(yǔ)言標(biāo)準(zhǔn)庫(kù)自帶的測(cè)試庫(kù)。在 Go 語(yǔ)言中編寫測(cè)試很簡(jiǎn)單,只需要遵循 Go 測(cè)試的幾個(gè)約定,與編寫正常的 Go 代碼沒有什么區(qū)別。Go 語(yǔ)言中有 3 種類型的測(cè)試:?jiǎn)卧獪y(cè)試,性能測(cè)試,示例測(cè)試。下面依次來介紹。

單元測(cè)試

單元測(cè)試又稱為功能性測(cè)試,是為了測(cè)試函數(shù)、模塊等代碼的邏輯是否正確。接下來我們編寫一個(gè)庫(kù),用于將表示羅馬數(shù)字的字符串和整數(shù)互轉(zhuǎn)。羅馬數(shù)字是由M/D/C/L/X/V/I這幾個(gè)字符根據(jù)一定的規(guī)則組合起來表示一個(gè)正整數(shù):

  • M=1000,D=500,C=100,L=50,X=10,V=5,I=1;
  • 只能表示 1-3999 范圍內(nèi)的整數(shù),不能表示 0 和負(fù)數(shù),不能表示 4000 及以上的整數(shù),不能表示分?jǐn)?shù)和小數(shù)(當(dāng)然有其他復(fù)雜的規(guī)則來表示這些數(shù)字,這里暫不考慮);
  • 每個(gè)整數(shù)只有一種表示方式,一般情況下,連寫的字符表示對(duì)應(yīng)整數(shù)相加,例如I=1II=2,III=3。但是,十位字符(I/X/C/M)最多出現(xiàn) 3 次,所以不能用IIII表示 4,需要在V左邊添加一個(gè)I(即IV)來表示,不能用VIIII表示 9,需要使用IX代替。另外五位字符(V/L/D)不能連續(xù)出現(xiàn) 2 次,所以不能出現(xiàn)VV,需要用X代替。
// roman.go
package roman
import (
  "bytes"
  "errors"
  "regexp"
)
type romanNumPair struct {
  Roman string
  Num   int
}
var (
  romanNumParis []romanNumPair
  romanRegex    *regexp.Regexp
)
var (
  ErrOutOfRange   = errors.New("out of range")
  ErrInvalidRoman = errors.New("invalid roman")
)
func init() {
  romanNumParis = []romanNumPair{
    {"M", 1000},
    {"CM", 900},
    {"D", 500},
    {"CD", 400},
    {"C", 100},
    {"XC", 90},
    {"L", 50},
    {"XL", 40},
    {"X", 10},
    {"IX", 9},
    {"V", 5},
    {"IV", 4},
    {"I", 1},
  }
  romanRegex = regexp.MustCompile(`^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$`)
}
func ToRoman(n int) (string, error) {
  if n <= 0 || n >= 4000 {
    return "", ErrOutOfRange
  }
  var buf bytes.Buffer
  for _, pair := range romanNumParis {
    for n > pair.Num {
      buf.WriteString(pair.Roman)
      n -= pair.Num
    }
  }
  return buf.String(), nil
}
func FromRoman(roman string) (int, error) {
  if !romanRegex.MatchString(roman) {
    return 0, ErrInvalidRoman
  }
  var result int
  var index int
  for _, pair := range romanNumParis {
    for roman[index:index+len(pair.Roman)] == pair.Roman {
      result += pair.Num
      index += len(pair.Roman)
    }
  }
  return result, nil
}

在 Go 中編寫測(cè)試很簡(jiǎn)單,只需要在待測(cè)試功能所在文件的同級(jí)目錄中創(chuàng)建一個(gè)以_test.go結(jié)尾的文件。在該文件中,我們可以編寫一個(gè)個(gè)測(cè)試函數(shù)。測(cè)試函數(shù)名必須是TestXxxx這個(gè)形式,而且Xxxx必須以大寫字母開頭,另外函數(shù)帶有一個(gè)*testing.T類型的參數(shù):

// roman_test.go
package roman
import (
  "testing"
)
func TestToRoman(t *testing.T) {
  _, err1 := ToRoman(0)
  if err1 != ErrOutOfRange {
    t.Errorf("ToRoman(0) expect error:%v got:%v", ErrOutOfRange, err1)
  }
  roman2, err2 := ToRoman(1)
  if err2 != nil {
    t.Errorf("ToRoman(1) expect nil error, got:%v", err2)
  }
  if roman2 != "I" {
    t.Errorf("ToRoman(1) expect:%s got:%s", "I", roman2)
  }
}

在測(cè)試函數(shù)中編寫的代碼與正常的代碼沒有什么不同,調(diào)用相應(yīng)的函數(shù),返回結(jié)果,判斷結(jié)果與預(yù)期是否一致,如果不一致則調(diào)用testing.TErrorf()輸出錯(cuò)誤信息。運(yùn)行測(cè)試時(shí),這些錯(cuò)誤信息會(huì)被收集起來,運(yùn)行結(jié)束后統(tǒng)一輸出。

測(cè)試編寫完成之后,使用go test命令運(yùn)行測(cè)試,輸出結(jié)果:

$ go test

--- FAIL: TestToRoman (0.00s)
    roman_test.go:18: ToRoman(1) expect:I got:
FAIL
exit status 1
FAIL    github.com/darjun/go-daily-lib/testing  0.172s

我故意將ToRoman()函數(shù)中寫錯(cuò)了一行代碼,n > pair.Num>應(yīng)該為>=,單元測(cè)試成功找出了錯(cuò)誤。修改之后重新運(yùn)行測(cè)試:

$ go test
PASS
ok      github.com/darjun/go-daily-lib/testing  0.178s

這次測(cè)試都通過了!

我們還可以給go test命令傳入-v選項(xiàng),輸出詳細(xì)的測(cè)試信息:

$ go test -v

=== RUN   TestToRoman
--- PASS: TestToRoman (0.00s)
PASS
ok      github.com/darjun/go-daily-lib/testing  0.174s

在運(yùn)行每個(gè)測(cè)試函數(shù)前,都輸出一行=== RUN,運(yùn)行結(jié)束之后輸出--- PASS--- FAIL信息。

表格驅(qū)動(dòng)測(cè)試

在上面的例子中,我們實(shí)際上只測(cè)試了兩種情況,0 和 1。按照這種方式將每種情況都寫出來就太繁瑣了,Go 中流行使用表格的方式將各個(gè)測(cè)試數(shù)據(jù)和結(jié)果列舉出來:

func TestToRoman(t *testing.T) {
  testCases := []struct {
    num    int
    expect string
    err    error
  }{
    {0, "", ErrOutOfRange},
    {1, "I", nil},
    {2, "II", nil},
    {3, "III", nil},
    {4, "IV", nil},
    {5, "V", nil},
    {6, "VI", nil},
    {7, "VII", nil},
    {8, "VIII", nil},
    {9, "IX", nil},
    {10, "X", nil},
    {50, "L", nil},
    {100, "C", nil},
    {500, "D", nil},
    {1000, "M", nil},
    {31, "XXXI", nil},
    {148, "CXLVIII", nil},
    {294, "CCXCIV", nil},
    {312, "CCCXII", nil},
    {421, "CDXXI", nil},
    {528, "DXXVIII", nil},
    {621, "DCXXI", nil},
    {782, "DCCLXXXII", nil},
    {870, "DCCCLXX", nil},
    {941, "CMXLI", nil},
    {1043, "MXLIII", nil},
    {1110, "MCX", nil},
    {1226, "MCCXXVI", nil},
    {1301, "MCCCI", nil},
    {1485, "MCDLXXXV", nil},
    {1509, "MDIX", nil},
    {1607, "MDCVII", nil},
    {1754, "MDCCLIV", nil},
    {1832, "MDCCCXXXII", nil},
    {1993, "MCMXCIII", nil},
    {2074, "MMLXXIV", nil},
    {2152, "MMCLII", nil},
    {2212, "MMCCXII", nil},
    {2343, "MMCCCXLIII", nil},
    {2499, "MMCDXCIX", nil},
    {2574, "MMDLXXIV", nil},
    {2646, "MMDCXLVI", nil},
    {2723, "MMDCCXXIII", nil},
    {2892, "MMDCCCXCII", nil},
    {2975, "MMCMLXXV", nil},
    {3051, "MMMLI", nil},
    {3185, "MMMCLXXXV", nil},
    {3250, "MMMCCL", nil},
    {3313, "MMMCCCXIII", nil},
    {3408, "MMMCDVIII", nil},
    {3501, "MMMDI", nil},
    {3610, "MMMDCX", nil},
    {3743, "MMMDCCXLIII", nil},
    {3844, "MMMDCCCXLIV", nil},
    {3888, "MMMDCCCLXXXVIII", nil},
    {3940, "MMMCMXL", nil},
    {3999, "MMMCMXCIX", nil},
    {4000, "", ErrOutOfRange},
  }
  for _, testCase := range testCases {
    got, err := ToRoman(testCase.num)
    if got != testCase.expect {
      t.Errorf("ToRoman(%d) expect:%s got:%s", testCase.num, testCase.expect, got)
    }
    if err != testCase.err {
      t.Errorf("ToRoman(%d) expect error:%v got:%v", testCase.num, testCase.err, err)
    }
  }
}

上面將要測(cè)試的每種情況列舉出來,然后針對(duì)每個(gè)整數(shù)調(diào)用ToRoman()函數(shù),比較返回的羅馬數(shù)字字符串和錯(cuò)誤值是否與預(yù)期的相符。后續(xù)要添加新的測(cè)試用例也很方便。

分組和并行

有時(shí)候?qū)ν粋€(gè)函數(shù)有不同維度的測(cè)試,將這些組合在一起有利于維護(hù)。例如上面對(duì)ToRoman()函數(shù)的測(cè)試可以分為非法值,單個(gè)羅馬字符和普通 3 種情況。

為了分組,我對(duì)代碼做了一定程度的重構(gòu),首先抽象一個(gè)toRomanCase結(jié)構(gòu):

type toRomanCase struct {
  num    int
  expect string
  err    error
}

將所有的測(cè)試數(shù)據(jù)劃分到 3 個(gè)組中:

var (
  toRomanInvalidCases []toRomanCase
  toRomanSingleCases  []toRomanCase
  toRomanNormalCases  []toRomanCase
)
func init() {
  toRomanInvalidCases = []toRomanCase{
    {0, "", roman.ErrOutOfRange},
    {4000, "", roman.ErrOutOfRange},
  }
  toRomanSingleCases = []toRomanCase{
    {1, "I", nil},
    {5, "V", nil},
    // ...
  }
  toRomanNormalCases = []toRomanCase{
    {2, "II", nil},
    {3, "III", nil},
    // ...
  }
}

然后為了避免代碼重復(fù),抽象一個(gè)運(yùn)行多個(gè)toRomanCase的函數(shù):

func testToRomanCases(cases []toRomanCase, t *testing.T) {
  for _, testCase := range cases {
    got, err := roman.ToRoman(testCase.num)
    if got != testCase.expect {
      t.Errorf("ToRoman(%d) expect:%s got:%s", testCase.num, testCase.expect, got)
    }
    if err != testCase.err {
      t.Errorf("ToRoman(%d) expect error:%v got:%v", testCase.num, testCase.err, err)
    }
  }
}

為每個(gè)分組定義一個(gè)測(cè)試函數(shù):

func testToRomanInvalid(t *testing.T) {
  testToRomanCases(toRomanInvalidCases, t)
}
func testToRomanSingle(t *testing.T) {
  testToRomanCases(toRomanSingleCases, t)
}
func testToRomanNormal(t *testing.T) {
  testToRomanCases(toRomanNormalCases, t)
}

在原來的測(cè)試函數(shù)中,調(diào)用t.Run()運(yùn)行不同分組的測(cè)試函數(shù),t.Run()第一個(gè)參數(shù)為子測(cè)試名,第二個(gè)參數(shù)為子測(cè)試函數(shù):

func TestToRoman(t *testing.T) {
  t.Run("Invalid", testToRomanInvalid)
  t.Run("Single", testToRomanSingle)
  t.Run("Normal", testToRomanNormal)
}

運(yùn)行:

$ go test -v

=== RUN   TestToRoman
=== RUN   TestToRoman/Invalid
=== RUN   TestToRoman/Single
=== RUN   TestToRoman/Normal
--- PASS: TestToRoman (0.00s)
    --- PASS: TestToRoman/Invalid (0.00s)
    --- PASS: TestToRoman/Single (0.00s)
    --- PASS: TestToRoman/Normal (0.00s)
PASS
ok      github.com/darjun/go-daily-lib/testing  0.188s

可以看到,依次運(yùn)行 3 個(gè)子測(cè)試,子測(cè)試名是父測(cè)試名和t.Run()指定的名字組合而成的,如TestToRoman/Invalid。

默認(rèn)情況下,這些測(cè)試都是依次順序執(zhí)行的。如果各個(gè)測(cè)試之間沒有聯(lián)系,我們可以讓他們并行以加快測(cè)試速度。方法也很簡(jiǎn)單,在testToRomanInvalid/testToRomanSingle/testToRomanNormal這 3 個(gè)函數(shù)開始處調(diào)用t.Parallel(),由于這 3 個(gè)函數(shù)直接調(diào)用了testToRomanCases,也可以只在testToRomanCases函數(shù)開頭出添加:

func testToRomanCases(cases []toRomanCase, t *testing.T) {
  t.Parallel()
  // ...
}

運(yùn)行:

$ go test -v
...
--- PASS: TestToRoman (0.00s)
    --- PASS: TestToRoman/Invalid (0.00s)
    --- PASS: TestToRoman/Normal (0.00s)
    --- PASS: TestToRoman/Single (0.00s)
PASS
ok      github.com/darjun/go-daily-lib/testing  0.182s

我們發(fā)現(xiàn)測(cè)試完成的順序并不是我們指定的順序。

另外,這個(gè)示例中我將roman_test.go文件移到了roman_test包中,所以需要import "github.com/darjun/go-daily-lib/testing/roman"。這種方式在測(cè)試包有循環(huán)依賴的情況下非常有用,例如標(biāo)準(zhǔn)庫(kù)中net/http依賴net/url,url的測(cè)試函數(shù)依賴net/http,如果把測(cè)試放在net/url包中,那么就會(huì)導(dǎo)致循環(huán)依賴url_test(net/url)->net/http->net/url。這時(shí)可以將url_test放在一個(gè)獨(dú)立的包中。

主測(cè)試函數(shù)

有一種特殊的測(cè)試函數(shù),函數(shù)名為TestMain(),接受一個(gè)*testing.M類型的參數(shù)。這個(gè)函數(shù)一般用于在運(yùn)行所有測(cè)試前執(zhí)行一些初始化邏輯(如創(chuàng)建數(shù)據(jù)庫(kù)鏈接),或所有測(cè)試都運(yùn)行結(jié)束之后執(zhí)行一些清理邏輯(釋放數(shù)據(jù)庫(kù)鏈接)。如果測(cè)試文件中定義了這個(gè)函數(shù),則go test命令會(huì)直接運(yùn)行這個(gè)函數(shù),否者go test會(huì)創(chuàng)建一個(gè)默認(rèn)的TestMain()函數(shù)。這個(gè)函數(shù)的默認(rèn)行為就是運(yùn)行文件中定義的測(cè)試。我們自定義TestMain()函數(shù)時(shí),也需要手動(dòng)調(diào)用m.Run()方法運(yùn)行測(cè)試函數(shù),否則測(cè)試函數(shù)不會(huì)運(yùn)行。默認(rèn)的TestMain()類似下面代碼:

func TestMain(m *testing.M) {
  os.Exit(m.Run())
}

下面自定義一個(gè)TestMain()函數(shù),打印go test支持的選項(xiàng):

func TestMain(m *testing.M) {
  flag.Parse()
  flag.VisitAll(func(f *flag.Flag) {
    fmt.Printf("name:%s usage:%s value:%v\n", f.Name, f.Usage, f.Value)
  })
  os.Exit(m.Run())
}

運(yùn)行:

$ go test -v
name:test.bench usage:run only benchmarks matching `regexp` value:
name:test.benchmem usage:print memory allocations for benchmarks value:false
name:test.benchtime usage:run each benchmark for duration `d` value:1s
name:test.blockprofile usage:write a goroutine blocking profile to `file` value:
name:test.blockprofilerate usage:set blocking profile `rate` (see runtime.SetBlockProfileRate) value:1
name:test.count usage:run tests and benchmarks `n` times value:1
name:test.coverprofile usage:write a coverage profile to `file` value:
name:test.cpu usage:comma-separated `list` of cpu counts to run each test with value:
name:test.cpuprofile usage:write a cpu profile to `file` value:
name:test.failfast usage:do not start new tests after the first test failure value:false
name:test.list usage:list tests, examples, and benchmarks matching `regexp` then exit value:
name:test.memprofile usage:write an allocation profile to `file` value:
name:test.memprofilerate usage:set memory allocation profiling `rate` (see runtime.MemProfileRate) value:0
name:test.mutexprofile usage:write a mutex contention profile to the named file after execution value:
name:test.mutexprofilefraction usage:if >= 0, calls runtime.SetMutexProfileFraction() value:1
name:test.outputdir usage:write profiles to `dir` value:
name:test.paniconexit0 usage:panic on call to os.Exit(0) value:true
name:test.parallel usage:run at most `n` tests in parallel value:8
name:test.run usage:run only tests and examples matching `regexp` value:
name:test.short usage:run smaller test suite to save time value:false
name:test.testlogfile usage:write test action log to `file` (for use only by cmd/go) value:
name:test.timeout usage:panic test binary after duration `d` (default 0, timeout disabled) value:10m0s
name:test.trace usage:write an execution trace to `file` value:
name:test.v usage:verbose: print additional output value:tru

這些選項(xiàng)也可以通過go help testflag查看。

其他

另一個(gè)函數(shù)FromRoman()我沒有寫任何測(cè)試,就交給大家了??

性能測(cè)試

性能測(cè)試是為了對(duì)函數(shù)的運(yùn)行性能進(jìn)行評(píng)測(cè)。性能測(cè)試也必須在_test.go文件中編寫,且函數(shù)名必須是BenchmarkXxxx開頭。性能測(cè)試函數(shù)接受一個(gè)*testing.B的參數(shù)。下面我們編寫 3 個(gè)計(jì)算第 n 個(gè)斐波那契數(shù)的函數(shù)。

第一種方式:遞歸

func Fib1(n int) int {
  if n <= 1 {
    return n
  }
  return Fib1(n-1) + Fib1(n-2)
}

第二種方式:備忘錄

func fibHelper(n int, m map[int]int) int {
  if n <= 1 {
    return n
  }
  if v, ok := m[n]; ok {
    return v
  }
  v := fibHelper(n-2, m) + fibHelper(n-1, m)
  m[n] = v
  return v
}
func Fib2(n int) int {
  m := make(map[int]int)
  return fibHelper(n, m)
}

第三種方式:迭代

func Fib3(n int) int {
  if n <= 1 {
    return n
  }
  f1, f2 := 0, 1
  for i := 2; i <= n; i++ {
    f1, f2 = f2, f1+f2
  }
  return f2
}

下面我們來測(cè)試這 3 個(gè)函數(shù)的執(zhí)行效率:

// fib_test.go
func BenchmarkFib1(b *testing.B) {
  for i := 0; i < b.N; i++ {
    Fib1(20)
  }
}
func BenchmarkFib2(b *testing.B) {
  for i := 0; i < b.N; i++ {
    Fib2(20)
  }
}
func BenchmarkFib3(b *testing.B) {
  for i := 0; i < b.N; i++ {
    Fib3(20)
  }
}

需要特別注意的是Ngo test會(huì)一直調(diào)整這個(gè)數(shù)值,直到測(cè)試時(shí)間能得出可靠的性能數(shù)據(jù)為止。運(yùn)行:

$ go test -bench=.
goos: windows
goarch: amd64
pkg: github.com/darjun/go-daily-lib/testing/fib
cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
BenchmarkFib1-8            31110             39144 ns/op
BenchmarkFib2-8           582637              3127 ns/op
BenchmarkFib3-8         191600582            5.588 ns/op
PASS
ok      github.com/darjun/go-daily-lib/testing/fib      5.225s

性能測(cè)試默認(rèn)不會(huì)執(zhí)行,需要通過-bench=.指定運(yùn)行。-bench選項(xiàng)的值是一個(gè)簡(jiǎn)單的模式,.表示匹配所有的,Fib表示運(yùn)行名字中有Fib的。

上面的測(cè)試結(jié)果表示Fib1在指定時(shí)間內(nèi)執(zhí)行了 31110 次,平均每次 39144 ns,Fib2在指定時(shí)間內(nèi)運(yùn)行了 582637 次,平均每次耗時(shí) 3127 ns,Fib3在指定時(shí)間內(nèi)運(yùn)行了 191600582 次,平均每次耗時(shí) 5.588 ns。

其他選項(xiàng)

有一些選項(xiàng)可以控制性能測(cè)試的執(zhí)行。

-benchtime:設(shè)置每個(gè)測(cè)試的運(yùn)行時(shí)間。

$ go test -bench=. -benchtime=30s

運(yùn)行了更長(zhǎng)的時(shí)間:

$ go test -bench=. -benchtime=30s
goos: windows
goarch: amd64
pkg: github.com/darjun/go-daily-lib/testing/fib
cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
BenchmarkFib1-8           956464             38756 ns/op
BenchmarkFib2-8         17862495              2306 ns/op
BenchmarkFib3-8       1000000000             5.591 ns/op
PASS
ok      github.com/darjun/go-daily-lib/testing/fib      113.498s

-benchmem:輸出性能測(cè)試函數(shù)的內(nèi)存分配情況。

-memprofile file:將內(nèi)存分配數(shù)據(jù)寫入文件。

-cpuprofile file:將 CPU 采樣數(shù)據(jù)寫入文件,方便使用go tool pprof工具分析,詳見我的另一篇文章《你不知道的 Go 之 pprof》

運(yùn)行:

$ go test -bench=. -benchtime=10s -cpuprofile=./cpu.prof -memprofile=./mem.prof
goos: windows
goarch: amd64
pkg: github.com/darjun/fib
BenchmarkFib1-16          356006             33423 ns/op
BenchmarkFib2-16         8958194              1340 ns/op
BenchmarkFib3-16        1000000000               6.60 ns/op
PASS
ok      github.com/darjun/fib   33.321s

同時(shí)生成了 CPU 采樣數(shù)據(jù)和內(nèi)存分配數(shù)據(jù),通過go tool pprof分析:

$ go tool pprof ./cpu.prof
Type: cpu
Time: Aug 4, 2021 at 10:21am (CST)
Duration: 32.48s, Total samples = 36.64s (112.81%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top10
Showing nodes accounting for 29640ms, 80.90% of 36640ms total
Dropped 153 nodes (cum <= 183.20ms)
Showing top 10 nodes out of 74
      flat  flat%   sum%        cum   cum%
   11610ms 31.69% 31.69%    11620ms 31.71%  github.com/darjun/fib.Fib1
    6490ms 17.71% 49.40%     6680ms 18.23%  github.com/darjun/fib.Fib3
    2550ms  6.96% 56.36%     8740ms 23.85%  runtime.mapassign_fast64
    2050ms  5.59% 61.95%     2060ms  5.62%  runtime.stdcall2
    1620ms  4.42% 66.38%     2140ms  5.84%  runtime.mapaccess2_fast64
    1480ms  4.04% 70.41%    12350ms 33.71%  github.com/darjun/fib.fibHelper
    1480ms  4.04% 74.45%     2960ms  8.08%  runtime.evacuate_fast64
    1050ms  2.87% 77.32%     1050ms  2.87%  runtime.memhash64
     760ms  2.07% 79.39%      760ms  2.07%  runtime.stdcall7
     550ms  1.50% 80.90%     7230ms 19.73%  github.com/darjun/fib.BenchmarkFib3
(pprof)

內(nèi)存:

$ go tool pprof ./mem.prof
Type: alloc_space
Time: Aug 4, 2021 at 10:30am (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top10
Showing nodes accounting for 8.69GB, 100% of 8.69GB total
Dropped 12 nodes (cum <= 0.04GB)
      flat  flat%   sum%        cum   cum%
    8.69GB   100%   100%     8.69GB   100%  github.com/darjun/fib.fibHelper
         0     0%   100%     8.69GB   100%  github.com/darjun/fib.BenchmarkFib2
         0     0%   100%     8.69GB   100%  github.com/darjun/fib.Fib2 (inline)
         0     0%   100%     8.69GB   100%  testing.(*B).launch
         0     0%   100%     8.69GB   100%  testing.(*B).runN
(pprof)

示例測(cè)試

示例測(cè)試用于演示模塊或函數(shù)的使用。同樣地,示例測(cè)試也在文件_test.go中編寫,并且示例測(cè)試函數(shù)名必須是ExampleXxx的形式。在Example*函數(shù)中編寫代碼,然后在注釋中編寫期望的輸出,go test會(huì)運(yùn)行該函數(shù),然后將實(shí)際輸出與期望的做比較。下面摘取自 Go 源碼net/url/example_test.go文件中的代碼演示了url.Values的用法:

func ExampleValuesGet() {
  v := url.Values{}
  v.Set("name", "Ava")
  v.Add("friend", "Jess")
  v.Add("friend", "Sarah")
  v.Add("friend", "Zoe")
  fmt.Println(v.Get("name"))
  fmt.Println(v.Get("friend"))
  fmt.Println(v["friend"])
  // Output:
  // Ava
  // Jess
  // [Jess Sarah Zoe]
}

注釋中Output:后是期望的輸出結(jié)果,go test會(huì)運(yùn)行這些函數(shù)并與期望的結(jié)果做比較,比較會(huì)忽略空格。

有時(shí)候我們輸出的順序是不確定的,這時(shí)就需要使用Unordered Output。我們知道url.Values底層類型為map[string][]string,所以可以遍歷輸出所有的鍵值,但是輸出順序不確定:

func ExampleValuesAll() {
  v := url.Values{}
  v.Set("name", "Ava")
  v.Add("friend", "Jess")
  v.Add("friend", "Sarah")
  v.Add("friend", "Zoe")
  for key, values := range v {
    fmt.Println(key, values)
  }
  // Unordered Output:
  // name [Ava]
  // friend [Jess Sarah Zoe]
}

運(yùn)行:

$ go test -v
$ go test -v

=== RUN   ExampleValuesGet
--- PASS: ExampleValuesGet (0.00s)
=== RUN   ExampleValuesAll
--- PASS: ExampleValuesAll (0.00s)
PASS
ok      github.com/darjun/url   0.172s

沒有注釋,或注釋中無Output/Unordered Output的函數(shù)會(huì)被忽略。

總結(jié)

本文介紹了 Go 中的 3 種測(cè)試:?jiǎn)卧獪y(cè)試,性能測(cè)試和示例測(cè)試。為了讓程序更可靠,讓以后的重構(gòu)更安全、更放心,單元測(cè)試必不可少。排查程序中的性能問題,性能測(cè)試能派上大用場(chǎng)。示例測(cè)試主要是為了演示如何使用某個(gè)功能。

參考

以上就是Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言測(cè)試庫(kù)testing的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Gotorch多機(jī)定時(shí)任務(wù)管理系統(tǒng)

    詳解Gotorch多機(jī)定時(shí)任務(wù)管理系統(tǒng)

    遵循著“學(xué)一門語(yǔ)言最好的方式是使用它”的理念,想著用Go來實(shí)現(xiàn)些什么,剛好有一個(gè)比較讓我煩惱的問題,于是用Go解決一下,即使不在生產(chǎn)環(huán)境使用,也可以作為Go語(yǔ)言學(xué)習(xí)的一種方式。
    2021-05-05
  • Go語(yǔ)法糖之‘...’ 的使用實(shí)例詳解

    Go語(yǔ)法糖之‘...’ 的使用實(shí)例詳解

    語(yǔ)法糖(Syntactic sugar),也譯為糖衣語(yǔ)法,指計(jì)算機(jī)語(yǔ)言中添加的某種語(yǔ)法,這種語(yǔ)法對(duì)語(yǔ)言的功能并沒有影響,但是更方便程序員使用。這篇文章主要給大家介紹Go語(yǔ)法糖之‘...’ 的使用,感興趣的朋友一起看看吧
    2018-10-10
  • golang調(diào)用shell命令(實(shí)時(shí)輸出,終止)

    golang調(diào)用shell命令(實(shí)時(shí)輸出,終止)

    本文主要介紹了golang調(diào)用shell命令(實(shí)時(shí)輸出,終止),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Go設(shè)計(jì)模式之生成器模式詳細(xì)講解

    Go設(shè)計(jì)模式之生成器模式詳細(xì)講解

    生成器模式將一個(gè)復(fù)雜對(duì)象的構(gòu)建和它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。生成器模式的主要功能是構(gòu)建復(fù)雜的產(chǎn)品,而且是細(xì)化地、分步驟地構(gòu)建產(chǎn)品,也就是說生成器模式重在一步一步解決構(gòu)建復(fù)雜對(duì)象的問題
    2023-01-01
  • Golang 協(xié)程配合管道的實(shí)現(xiàn)示例

    Golang 協(xié)程配合管道的實(shí)現(xiàn)示例

    本文主要介紹了Golang協(xié)程配合管道的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • VSCode Golang dlv調(diào)試數(shù)據(jù)截?cái)鄦栴}及處理方法

    VSCode Golang dlv調(diào)試數(shù)據(jù)截?cái)鄦栴}及處理方法

    這篇文章主要介紹了VSCode Golang dlv調(diào)試數(shù)據(jù)截?cái)鄦栴},本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • GoLang jwt無感刷新與SSO單點(diǎn)登錄限制解除方法詳解

    GoLang jwt無感刷新與SSO單點(diǎn)登錄限制解除方法詳解

    這篇文章主要介紹了GoLang jwt無感刷新與SSO單點(diǎn)登錄限制解除方法,JWT是一個(gè)簽名的JSON對(duì)象,通常用作Oauth2的Bearer token,JWT包括三個(gè)用.分割的部分。本文將利用JWT進(jìn)行認(rèn)證和加密,感興趣的可以了解一下
    2023-03-03
  • 一文帶你探索Golang計(jì)時(shí)器的奧秘

    一文帶你探索Golang計(jì)時(shí)器的奧秘

    在?Golang?中,計(jì)時(shí)器(timer)是一種常見的工具,用于定期執(zhí)行某個(gè)任務(wù)或者在指定時(shí)間后觸發(fā)某個(gè)事件。本文將深入探討?Golang?計(jì)時(shí)器的實(shí)現(xiàn)原理和使用方法,幫助大家更好地理解和應(yīng)用計(jì)時(shí)器
    2023-05-05
  • 重學(xué)Go語(yǔ)言之運(yùn)算符與控制結(jié)構(gòu)詳解

    重學(xué)Go語(yǔ)言之運(yùn)算符與控制結(jié)構(gòu)詳解

    對(duì)于任何編程語(yǔ)言來說,運(yùn)算符和控制結(jié)構(gòu)都算是最基礎(chǔ)的知識(shí)了,既然是基礎(chǔ),當(dāng)然非常有必要學(xué)習(xí),因此在這篇文章中我們就來討論一下
    2023-02-02
  • golang http請(qǐng)求封裝代碼

    golang http請(qǐng)求封裝代碼

    這篇文章主要介紹了golang http請(qǐng)求封裝代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評(píng)論