• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >Golang > 一步步教你编写可测试的Go语言代码

一步步教你编写可测试的Go语言代码

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了易语言怎么编写代码,用c语言编写的代码,c语言编写的代码程序,c语言编写代码,易语言编写代码等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

第一个测试 “Hello Test!”

首先,在我们$GOPATH/src目录下创建hello目录,作为本文涉及到的所有示例代码的根目录。

然后,新建名为hello.go的文件,定义一个函数hello() ,功能是返回一个由若干单词拼接成句子:

package hello

func hello() string {
 words := []string{"hello", "func", "in", "package", "hello"}
 wl := len(words)

 sentence := ""
 for key, word := range words {
  sentence += word
  if key < wl-1 {
   sentence += " "
  } else {
   sentence += "."
  }
 }
 return sentence
}
</div>

接着,新建名为hello_test.go的文件,填入如下内容:

package hello

import (
 "fmt"
 "testing"
)

func TestHello(t *testing.T) {
 got := hello()
 expect := "hello func in package hello."

 if got != expect {
  t.Errorf("got [%s] expected [%s]", got, expect)
 }
}

func BenchmarkHello(b *testing.B) {
 for i := 0; i < b.N; i++ {
  hello()
 }
}

func ExampleHello() {
 hl := hello()
 fmt.Println(hl)
 // Output: hello func in package hello.
}
</div>

最后,打开终端,进入hello目录,输入go test命令并回车,可以看到如下输出:

PASS
ok  hello 0.007s
</div>

编写测试代码

Golang的测试代码位于某个包的源代码中名称以_test.go结尾的源文件里,测试代码包含测试函数、测试辅助代码和示例函数;测试函数有以Test开头的功能测试函数和以Benchmark开头的性能测试函数两种,测试辅助代码是为测试函数服务的公共函数、初始化函数、测试数据等,示例函数则是以Example开头的说明被测试函数用法的函数。

大部分情况下,测试代码是作为某个包的一部分,意味着它可以访问包中不可导出的元素。但在有需要的时候(如避免循环依赖)也可以修改测试文件的包名,如package hello的测试文件,包名可以设为package hello_test。

功能测试函数

功能测试函数需要接收*testing.T类型的单一参数t,testing.T 类型用来管理测试状态和支持格式化的测试日志。测试日志在测试执行过程中积累起来,完成后输出到标准错误输出。

下面是从Go标准库摘抄的 testing.T类型的常用方法的用法:

测试函数中的某条测试用例执行结果与预期不符时,调用t.Error()或t.Errorf()方法记录日志并标记测试失败

# /usr/local/go/src/bytes/compare_test.go
func TestCompareIdenticalSlice(t *testing.T) {
 var b = []byte("Hello Gophers!")
 if Compare(b, b) != 0 {
  t.Error("b != b")
 }
 if Compare(b, b[:1]) != 1 {
  t.Error("b > b[:1] failed")
 }
}
</div>

使用t.Fatal()和t.Fatalf()方法,在某条测试用例失败后就跳出该测试函数

# /usr/local/go/src/bytes/reader_test.go
func TestReadAfterBigSeek(t *testing.T) {
 r := NewReader([]byte("0123456789"))
 if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
  t.Fatal(err)
 }
 if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
  t.Errorf("Read = %d, %v; want 0, EOF", n, err)
 }
}
</div>

使用t.Skip()和t.Skipf()方法,跳过某条测试用例的执行

# /usr/local/go/src/archive/zip/zip_test.go
func TestZip64(t *testing.T) {
 if testing.Short() {
  t.Skip("slow test; skipping")
 }
 const size = 1 << 32 // before the "END\n" part
 buf := testZip64(t, size)
 testZip64DirectoryRecordLength(buf, t)
}
</div>

执行测试用例的过程中通过t.Log()和t.Logf()记录日志

# /usr/local/go/src/regexp/exec_test.go
func TestFowler(t *testing.T) {
 files, err := filepath.Glob("testdata/*.dat")
 if err != nil {
  t.Fatal(err)
 }
 for _, file := range files {
  t.Log(file)
  testFowler(t, file)
 }
}
</div>

使用t.Parallel()标记需要并发执行的测试函数

# /usr/local/go/src/runtime/stack_test.go
func TestStackGrowth(t *testing.T) {
 t.Parallel()
 var wg sync.WaitGroup

 // in a normal goroutine
 wg.Add(1)
 go func() {
  defer wg.Done()
  growStack()
 }()
 wg.Wait()

 // ...
}
</div>

性能测试函数

性能测试函数需要接收*testing.B类型的单一参数b,性能测试函数中需要循环b.N次调用被测函数。testing.B 类型用来管理测试时间和迭代运行次数,也支持和testing.T相同的方式管理测试状态和格式化的测试日志,不一样的是testing.B的日志总是会输出。

下面是从Go标准库摘抄的 testing.B类型的常用方法的用法:

在函数中调用t.ReportAllocs() ,启用内存使用分析

# /usr/local/go/src/bufio/bufio_test.go
func BenchmarkWriterFlush(b *testing.B) {
 b.ReportAllocs()
 bw := NewWriter(ioutil.Discard)
 str := strings.Repeat("x", 50)
 for i := 0; i < b.N; i++ {
  bw.WriteString(str)
  bw.Flush()
 }
}
</div>

通过 b.StopTimer() 、b.ResetTimer() 、b.StartTimer()来停止、重置、启动 时间经过和内存分配计数

# /usr/local/go/src/fmt/scan_test.go
func BenchmarkScanInts(b *testing.B) {
 b.ResetTimer()
 ints := makeInts(intCount)
 var r RecursiveInt
 for i := b.N - 1; i >= 0; i-- {
  buf := bytes.NewBuffer(ints)
  b.StartTimer()
  scanInts(&r, buf)
  b.StopTimer()
 }
}
</div>

调用b.SetBytes()记录在一个操作中处理的字节数

# /usr/local/go/src/testing/benchmark.go
func BenchmarkFields(b *testing.B) {
 b.SetBytes(int64(len(fieldsInput)))
 for i := 0; i < b.N; i++ {
  Fields(fieldsInput)
 }
}
</div>

通过b.RunParallel()方法和 *testing.PB类型的Next()方法来并发执行被测对象

# /usr/local/go/src/sync/atomic/value_test.go
func BenchmarkValueRead(b *testing.B) {
 var v Value
 v.Store(new(int))
 b.RunParallel(func(pb *testing.PB) {
  for pb.Next() {
   x := v.Load().(*int)
   if *x != 0 {
    b.Fatalf("wrong value: got %v, want 0", *x)
   }
  }
 })
}
</div>

测试辅助代码

测试辅助代码是编写测试代码过程中因代码重用和代码质量考虑而产生的。主要包括如下方面:

引入依赖的外部包,如每个测试文件都需要的 testing 包等:

# /usr/local/go/src/log/log_test.go:
import (
 "bytes"
 "fmt"
 "os"
 "regexp"
 "strings"
 "testing"
 "time"
)
</div>

定义多次用到的常量和变量,测试用例数据等:

# /usr/local/go/src/log/log_test.go:
const (
 Rdate   = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
 Rtime   = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
 Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
 Rline   = `(57|59):` // must update if the calls to l.Printf / l.Print below move
 Rlongfile  = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
 Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline
)

// ...

var tests = []tester{
 // individual pieces:
 {0, "", ""},
 {0, "XXX", "XXX"},
 {Ldate, "", Rdate + " "},
 {Ltime, "", Rtime + " "},
 {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
 {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
 {Llongfile, "", Rlongfile + " "},
 {Lshortfile, "", Rshortfile + " "},
 {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
 // everything at once:
 {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + R
  


 

您可能想查找下面的文章:

  • 一步步教你编写可测试的Go语言代码

相关文章

  • Go语言开发环境搭建与初探(Windows平台下)
  • Go语言中的复合类型详细介绍
  • go语言通过管道连接两个命令行进程的方法
  • go的websocket实现原理与用法详解
  • Go语言的队列和堆栈实现方法
  • CentOS 32 bit安装golang 1.7的步骤详解
  • 从Node.js 转到 Go平台
  • GO语言(golang)基础知识
  • Go语言实现汉诺塔算法
  • Go语言服务器开发实现最简单HTTP的GET与POST接口

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • 我为什么喜欢Go语言(简洁的Go语言)
    • Go语言里的new函数用法分析
    • go语言制作端口扫描器
    • 利用Go语言初步搭建一个web应用的教程
    • 一步步教你编写可测试的Go语言代码
    • golang两种调用rpc的方法
    • Go语言对字符串进行MD5加密的方法
    • Go语言RPC Authorization进行简单ip安全验证的方法
    • Go语言多值替换的HTML模板实例分析
    • 在Visual Studio Code中配置GO开发环境的详细教程

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有