• golang 之单元测试


    测试

      测试是自动化测试的简称,即编写简单的程序来确保程序(产品代码)在测试中针对特定输入产生预期的输出。Go的测试方法看上去相对比较低级,它依赖于命令go test和一些能用go test运行的测试函数的编写约定

    go test 工具

      go test 子命令是Go语言包的测试驱动程序,这些包根据某些约定组织在一起。在一个包目录中,以_test.go结尾的文件不是go build命令编译的目标,而是go test编译的目标。

      在*_test.go文件中,三种函数需要特殊对待,即

    1. 功能测试函数
    2. 基准测试函数 :名称以benchmark开头,用来检测某些操作的性能。
    3. 示例运行测试函数 :以Example来测试某些操作的性能。用来提供机器检查过的文档。

    Test 函数

      每一个测试文件必须导入testing包,签名如下

    import "testing"
    
    func TestName(t *testing.T)  {
    	
    }
    

     功能测试函数必须以Test开头,可选的后缀名称必须以大写字母开头:

    import "testing"
    
    func TestSin(t *testing.T)  {
    	
    }
    
    func TestCos(t *testing.T)  {
    	
    }
    

    示例 

      如下编译一个测试连接mysql的单元测试,必须保证同目录的情况下,否则找不到,创建一个mysql.go用来编写连接的代码

    package mysql
    
    import (
        "database/sql"
        _ "github.com/go-sql-driver/mysql"
    )
    
    func findByPk(pk int) int {
        var num int = 0
        db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/plugin?charset=utf8")
        if err != nil {
            panic(err.Error())
        }
        defer db.Close()
        stmtOut, err := db.Prepare("select id from t_admin where id=?")
        if err != nil {
            panic(err.Error())
        }
        defer stmtOut.Close()
    
        err = stmtOut.QueryRow(pk).Scan(&num)
        if err != nil {
            panic(err.Error())
        }
        return num
    }
    

     在同目录下创建一个mysql_test.go用来编写测试代码

    package mysql
    
    import (
        "testing"
    )
    
    func Test_findByPk(t *testing.T) {
        num := findByPk(1)
        t.Log(num)
    }
    

     运行

    • go test: 在当前目录下运行所有测试用例 
    • go test -file *_test.go : 运行指定测试文件。如 go test -file mysql_test.go
    • go test -V: 显示详细结果
    • go test -run="Test_XXX" : 指定运行某个方法

    测试覆盖率

      一个测试套件覆盖待测试包的比例称为测试的覆盖率。覆盖率无法直接通过数量来衡量。任何事情都是动态的。即使最微小的程序都无法精准的测量。语句覆盖率是指部分语句在一次执行中至少执行一次。go语言中提供cover工具

    # go test -cover
    PASS
    coverage: 100.0% of statements
    ok    jdGoBackend/library/sdk/jd      0.017s
    

      go还提供了将输出打印报告的方法。

    # go test -cover -coverprofile=c.out
    

     然后可以通过html方法显示,使用cover工具来处理生成的记录信息,该命令会打开本地的浏览器窗口生成一个HTML报告。

    # go tool cover -html=c.out  

    基准测试 

      基准测试是在一定的工作负载之下检测程序性能的一种方法,在Go里面,基准测试函数看上去像一个测试函数。但前缀是Benchmark并且拥有一个*testing.B参数用来提供大多数和*testing.T相同的方法。额外增加一些与性能检测相关的方法。还提供了一个整数检测成员N,用来检测执行的次数。

      基本格式

    func BenchmarkName(b *testing.B){
        // ...
    }
    

      下面的基准测试在一个循环中调用了IsPaling共 N次

    import "testing"
    
    func BenchmarkIsPaling(b *testing.B)  {
    	for i:=0; i< b.N; i++{
    		IsPaling("aaaaa")
    	}
    }
    

     和测试不同的是,默认情况下不会执行任何基准测试,需要标记-bench的参数指定要运行的基准参数。

    #  go test -bench=IsPaling
    BenchmarkIsPaling-8        10000000               203 ns/op
    PASS
    ok      jdGoBackend/library/sdk/jd      2.255s
    

      就上面的运行结果,基础名称BenchmarkIsPaling-8后缀8表示GOMAXPROCS的值。这个数字对并发基准测试很重要。

      报告告诉我们每次IsPaling调用耗费0.23ms。这个是1 000 000 0次调用的平均值

    我们可以通过-benchmen再报告中包含了内存分配统计数据。这里和优化之前的内存分配进行比较。

    # go test -bench=. -benchmen  // . 通配符匹配所有
    PASS 
    BenchmarkIsPaling  1000000 1026 ns/op 304 B/op 4 allocs/op
    

     最后,性能比较函数知识普通的代码,它们的表现形式通常是带有一个参数的函数,被多个不同Benchmark函数传入不同的值来调用。如下

    func benchmark(b *testing.B, size int){/* ... */}
    func Benchmark10(b *testing.B){ benchmark(b, 10) }
    func Benchmark100(b *testing.B){ benchmark(b, 100) }
    func Benchmark1000(b *testing.B){ benchmark(b, 1000) }
    

     参数size指定了输入的大小,每个Benchmark函数传入的值都不同但是在每个函数内部是一个常量,不要使用b.N作为输入的大小。除非把它当作固定大小输入的循环次数。否则该基准测试的结果毫无意义。

    最后测试牵扯到性能,将会在性能模块详细介绍。

  • 相关阅读:
    原型污染
    C#之抛异常
    为什么['1', '7', '11'].map(parseInt) returns [1, NaN, 3]?
    Linux
    Linux
    Linux
    Linux
    Linux
    Linux
    其他
  • 原文地址:https://www.cnblogs.com/flash55/p/12391101.html
Copyright © 2020-2023  润新知