51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 704|回复: 1
打印 上一主题 下一主题

[原创] 单元测试、性能测试之golang

[复制链接]
  • TA的每日心情
    无聊
    前天 09:05
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2023-2-3 10:32:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    单元测试
      单元测试(Unit Tests, UT) 是一个优秀项目不可或缺的一部分,特别是在一些频繁变动和多人合作开发的项目中尤为重要。你或多或少都会有因为自己的提交,导致应用挂掉或服务宕机的经历。比如我就曾经就因为打印了sql,而忘记关闭,导致所有的接口异常(允悲)。还有就是如果你优化了一些代码逻辑,优化了某个函数。那么我们怎么保证我们的正确性呢?那么几个测试用例或许就可以解决这个问题。
      测试文件的命名
      go语言是支持单元测试的,测试文件是_test.go结尾的文件名。
      测试用例的命名
      测试用例名称一般命名为 Test 加上待测试的方法名。比如TestAdd(),测试用的参数有且只有一个,在这里是 t *testing.T。
      简单入门
      我们来写一个Add函数,创建文件add.go。
    1. package main
    2.   import "fmt"
    3.   func main() {
    4.   sum := Add(1, 2)
    5.   fmt.Println(sum)
    6.   }
    7.   func Add(a int, b int) int {
    8.   return a + b
    9.   }
    复制代码


    我们在add.go目录下创建一个add_test.go的测试文件。
    1. package main
    2.   import (
    3.   "testing"
    4.   )
    5.   func TestAdd(t *testing.T) {
    6.   testData := []struct {
    7.   a int
    8.   b int
    9.   c int
    10.   }{
    11.   {1, 2, 3},
    12.   {4, 5, 9},
    13.   {50, 5, 5},
    14.   }
    15.   ans := 0
    16.   for _, data := range testData {
    17.   if ans = Add(data.a, data.b); ans != data.c {
    18.   t.Errorf("%d + %d expected %d,but %d got", data.a, data.b, data.c, ans)
    19.   }
    20.   }
    21.   }
    复制代码


    我们先来认识一下ide调试工具,当然这些调试我们在命令也是可以运行的:
      ·Run 执行脚本
      · Debug 开启Debug模式
      · coverprofile 代码覆盖率
      · CPU Profiler cup分析
      · Memory Profiler 内存分析 对象、堆的分析和内存泄漏等
      · Blocking Profiler 记录 goroutine的阻塞情况,等待和同步情况,timer/channel通讯等各项细节
      · Mutex Profiler 互斥锁分析,包括各种竞争情况

      我通过ide运行一下:

      我们也可以使用ide的debug功能打断点调试:

      命令行测试,首先我们进入add.go目录:

      代码覆盖率
      IDE调试:

      我们使用命令行再试一下:
    1. zhangguofu@zhangguofudeMacBook-Pro add (master) $ go test -coverprofile=c.out
    2.   --- FAIL: TestAdd (0.00s)
    3.       add_test.go:20: 50 + 5 expected 5,but 55 got
    4.   FAIL
    5.   coverage: 33.3% of statements
    6.   exit status 1
    7.   FAIL    goapp/src/learngo/add   0.502s
    8.   zhangguofu@zhangguofudeMacBook-Pro add (master) $ ls
    9.   add.go      add_test.go c.out
    10.   zhangguofu@zhangguofudeMacBook-Pro add (master) $ cat c.out
    11.   mode: set
    12.   goapp/src/learngo/add/add.go:5.13,8.2 2 0
    13.   goapp/src/learngo/add/add.go:10.28,12.2 1 1
    复制代码


    我们发现多了一个c.out 文件,但是里面的内容我们看不太懂,我们借助工具go tool cover ,查看代码覆盖的相关命令帮助。

      我们使用` go tool cover -html=c.out``,此时会打开一个html页面,上面标注了我们代码覆盖的情况。

      性能测试
      ·我们通过一个获取最长不重复字符串函数来测试一下性能
      · 函数代码 在add.go文件中
    1.  /**
    2.   最大字符串不重复
    3.   */
    4.   func Repeat(s string) int {
    5.   //保持最大不重复串
    6.   lastOccur := make(map[string]int)
    7.   start := 0
    8.   max := 0
    9.   for k, v := range []rune(s) {
    10.   if index, ok := lastOccur[string(v)]; ok && start <= index {
    11.   start = index + 1
    12.   }
    13.   if max < k-start+1 {
    14.   max = k - start + 1
    15.   }
    16.   lastOccur[string(v)] = k
    17.   }
    18.   return max
    19.   }
    复制代码


    性能测试代码 在add_test.go文件中:
    1. func BenchmarkRepeat(b *testing.B) {
    2.   str := "不经历风雨,怎么见彩虹?没有人能随随便便成功"
    3.   data := struct {
    4.   content string
    5.   res     int
    6.   }{
    7.   str,
    8.   17,
    9.   }
    10.   for i := 0; i < b.N; i++ {
    11.   if len := Repeat(data.content); len != 17 {
    12.   b.Error("the program is wrong")
    13.   }
    14.   }
    15.   }
    复制代码



      结果是3ms左右,我们加长一点看看:
    1.  func BenchmarkRepeat(b *testing.B) {
    2.   str := "不经历风雨,怎么见彩虹?没有人能随随便便"
    3.   for i := 0; i < 20; i++ {
    4.   str += str
    5.   }
    6.   b.Logf("the len of str is %d", len(str))
    7.   b.ResetTimer() //忽略上面的计算时间
    8.   for i := 0; i < b.N; i++ {
    9.   Repeat(str)
    10.   }
    11.   }
    复制代码


    我们发现对于计算6m文件中的不重复字符串,程序执行了大概是16s左右,这个感觉很慢了,对不对,但是我们想看程序是时间花在哪里了。

      和代码覆盖率的命令类似。我执行命令:
    1.  zhangguofu@zhangguofudeMacBook-Pro add (master) $ go test -bench . -cpuprofile  cpu.out
    2.   goos: darwin
    3.   goarch: amd64
    4.   pkg: goapp/src/learngo/add
    5.   BenchmarkRepeat-8              1        1541179761 ns/op
    6.   --- BENCH: BenchmarkRepeat-8
    7.       add_test.go:33: the len of str is 62914560
    8.   PASS
    9.   ok      goapp/src/learngo/add   2.077s
    10.   zhangguofu@zhangguofudeMacBook-Pro add (master) $ ls
    11.   add.go      add.test    add_test.go c.out       cpu.out
    12.   zhangguofu@zhangguofudeMacBook-Pro add (master) $ less cpu.out  
    13.   "cpu.out" may be a binary file.  See it anyway?
    复制代码


    发现生成的cpu.out 是一个二进制文件,我们使用go tool pprof cpu.out 查看,进入交互模式。

      我输入web格式的,报错说需要安装Graphviz ,那就安装吧。
      再次输入 go tool pprof cpu.out 输入web没有报错了,但是此处我碰到一个个问题。就是我的虚拟机(mac上面装的win10)会默认打开svg 文件,很烦人。
      解决方式:

      并且设置谷歌浏览器为默认打开方式:

      最终,我们打开了这个文件,这里面箭头越粗,代表花费的时间越长,我们可以根据结果 对我们的程序进行优化,比如在这里,我们看到是string encode decode 很浪费时间,那么我们是不是可以选择更合适的数据类型来存储我们的数据呢,比如我们存的是 abc我爱中国 ,那么再计算中,来回转换是很麻烦的,我们是不是可以转换为int32来计算呢。

      golang的单元测试和性能测试就先到这里了。喜欢可以点赞哦!!






    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:26
  • 签到天数: 651 天

    连续签到: 19 天

    [LV.9]测试副司令

    2#
    发表于 2023-2-24 10:51:09 | 只看该作者
    实用工具,有帮助
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-23 02:07 , Processed in 0.067586 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表