zoukankan      html  css  js  c++  java
  • Golang测试包

    Golang测试包

    golang自带了测试包(testing),直接可以进行单元测试、性能分析、输出结果验证等。简单看着官方文档试了试,总结一下:

    目录结构和命令

    使用golang的测试包,需要遵循简单的目录结构

    测试代码放在待测试代码的目录下(一个包内),以_test.go结尾,例如如下目录结构,MyTest目录下有待测试的代码文件MyTest.go和测试代码MyTest_test.go

    .
    |-- bin
    |   `-- main
    |-- pkg
    |   `-- darwin_amd64
    |       `-- MyTest.a
    `-- src
        |-- MyTest
        |   |-- MyTest.go
        |   `-- MyTest_test.go
        `-- main
            `-- main.go

    直接在MyTest目录下执行go test命令即可,go test包含很多选项,可以参考Golang手册相关部分

    基本的测试函数

    待测试的MyTest.go源码如下:

    package MyTest
    
    import (
        "fmt"
    )
    
    type MyStruct struct {
        name string
    }
    
    func GetFieldValue(x *MyStruct) string {
        value := x.name
        return value
    }
    
    func SetFieldValue(x *MyStruct, value string) {
        fmt.Println("SetFieldValue()")
        x.name = value
    }

    对于MyTest_test.go,首先自然是要导入golang的测试包

    package MyTest
    import testing

    基本的测试函数以Test开头,后面接的字符串,第一个字符必须是数字或者大写,例如:

    func TestMytest(t *testing.T) {
        var st MyStruct
        SetFieldValue(&st, "hello")
        val := GetFieldValue(&st)
    
        if val != "hello" {
            t.Error("Set Field")
        }
    }

    T是testing包里定义的一个结构体,其包含了名为common的接口,提供了很多格式化输出的功能,golang提供了自动检查与调用测试函数的机制,测试函数的执行逻辑则需要编写者自行完成。

    执行go test 结果为:

    Call SetFieldValue()
    PASS
    ok      /go/src/MyTest 0.004s

    如果写成Testmytest,运行时会直接忽略掉该函数。得到的结果仍然为Pass,但是不会打印“Call SetFieldValue()”,也就是说测试函数实际没有执行。
    修改一下判断条件:

    func TestMytest(t *testing.T) {
        var st MyStruct
        SetFieldValue(&st, "hello")
        val := GetFieldValue(&st)
    
        if val != "world" {
            t.Error("Set Field")
        }
    }

    这个测试用例不会通过, 而Error函数的入参就是测试不通过时打印的信息:

    SetFieldValue()
    --- FAIL: TestMytest (0.00s)
        MyTest_test.go:15: Set Field
    FAIL
    exit status 1
    FAIL    _/Users/ronghuihe/Documents/code/golang/my/go/src/MyTest 0.004s

    这并不会中断测试程序,这个函数后面的部分仍然会执行,其他的测试函数也会执行。

    性能分析函数

    testing包还自带了性能分析功能,可评估代码执行性能。性能分析函数也可以放到前面的xxx_test.go文件内,命名以Benchmark开头,如:

    func BenchmarkGetFieldValue(b *testing.B) {
        var st MyStruct
        SetFieldValue(&st, "hello")
    
        for i := 0; i < b.N; i++ {
            GetFieldValue(&st)
        }
    }

    其中b.N的值在执行过程中会自动调整,使得循环可以执行足够多次,以便得到较为准确的单次结果:
    性能分析加-bench参数执行,即go test -bench . (不能漏了最后这个点,它表示执行所有的性能测试函数)

    BenchmarkGetFieldValue    SetFieldValue()
    SetFieldValue()
    SetFieldValue()
    SetFieldValue()
    SetFieldValue()
    SetFieldValue()
    2000000000             0.55 ns/op

    每次循环大约需要0.55ns。这里SetFieldValue()打印了多次,是因为BenchmarkGetFieldValue被调用了多次。
    分析testing包的源码benchmark.go里的launch函数和runN函数,可以看到golang会自行调节性能分析函数的调用次数。每次执行runN都会执行一次性能测试函数,而后根据运行时间,会确定后续的内部循环执行次数b.N,直到总的运行时间达到go test -benchtime指定的时间(如果没指定默认为1s)

    注意统计时间时,执行的是使用者编写的性能分析函数,如上例中的BenchmarkGetFieldValue,而最后输出的结果,表达的是for循环里函数的性能,因此for循环之前的代码执行时间很长的话,可能导致统计误差比较大,如果需要剔除for之前代码的影响,可以在for循环之前调用ResetTimer()接口重置本次统计的时间值:

    func BenchmarkGetFieldValue(b *testing.B) {
        var st MyStruct
        SetFieldValue(&st, "hello")
    
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            GetFieldValue(&st)
        }
    }
  • 相关阅读:
    关于程序员认知和编程学习,没有任何一篇文章会讲得如此透彻
    Found 1 slaves: Use of uninitialized value in printf at /usr/local/percona-toolkit/bin/pt-online-schema-change line 8489
    alert 多语言的处理
    #!/bin/sh & #!/bin/bash区别
    mysql 常用
    java.io.FileNotFoundException
    struts1 & jquery form 文件异步上传
    简单的数据库连接池实例(java语言)
    null id in com.rocky.** entry 错误处理
    java unsupported major.minor version 51.0 解决
  • 原文地址:https://www.cnblogs.com/faunjoe88/p/8524674.html
Copyright © 2011-2022 走看看