51Testing软件测试论坛

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

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 712|回复: 0
打印 上一主题 下一主题

[原创] 单元测试执行案例之GO语言

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

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2023-3-1 10:52:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    单元测试的概念
      Gopher一定要养成写单元测试的习惯,这样才能保证我们交付代码的质量,同时提升个人开发水平!
      什么是单元测试
      1. 最小的可测试单位,比如函数、对象的某个接口。
      2. 是[url=]软件开发[/url]过程中对最小单位进行正确性验证的测试工作。
      为什么要写单元测试
      1. 保证变更、重构的正确性,特别是在多人协作的项目中。
      2. 简化调试过程:可以快速定位到问题代码。
      3. 单元测试是最好的开发文档:单元测试给出具体函数的使用方法及边界值,是最好的示例代码。
      编写测试用例的原则
      1. 单一原则:一个测试用例只负责一个应用场景
      2. 原子性:结果只有两种情况:Pass/Fail
      3. 优先级:核心的组件、逻辑要优先测试
      4. 公共使用库: utils工具类库要重点覆盖
      Go约定的测试规则
      1. 单元测试的文件需要和被测试的文件在统一目录下,测试用例名称必须是xxx_test.go的格式。
      测试文件中包含三种类型的函数,单元测试函数、基准测试函数和示例函数。

      单元测试的实践过程
      编写一个简单的测试用例
      package service

      import "testing"

      func add(a, b int) int {
      return a + b
      }

      func TestAdd(t *testing.T) {
      a := 10
      b := 20
      wanted := 30
      actual := add(a, b)
      if wanted != actual {
      t.Errorf("[add函数的入参:%d %d] [期望值:%d] [实际结果:%d]", a, b, wanted, actual)
      }
      }


      执行当前单元测试的命令: go test -v .\user_test.go
      PS C:\Program Files\JetBrains\GoRepository\gf-demo-user\internal\service> go test -v .\user_test.go
      === RUN   TestAdd
      --- PASS: TestAdd (0.00s)
      PASS
      ok      command-line-arguments  0.075s


      执行当前目录下所有的测试用例(跳过某个测试函数),并导出到制定的输出文件:go test -v ./... --short=true -coverprofile cover.out
      PS C:\Program Files\JetBrains\GoRepository\gf-demo-user\internal\service> go test -v ./... --short=true -coverprofile cover.out
      === RUN   TestAdd
      --- PASS: TestAdd (0.00s)
      coverage: 0.0% of statements
      ok      github.com/gogf/gf-demo-user/v2/internal/service        0.121s  coverage: 0.0% of statements


      查看输出覆盖率的html文档:go tool cover --func=cover.out
      PS C:\Program Files\JetBrains\GoRepository\gf-demo-user\internal\service> go tool cover --func=cover.out
      github.com/gogf/gf-demo-user/v2/internal/service/biz_ctx.go:22:         BizCtx                  0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/biz_ctx.go:29:         RegisterBizCtx          0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/middleware.go:19:      Middleware              0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/middleware.go:26:      RegisterMiddleware      0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/session.go:21:         Session                 0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/session.go:28:         RegisterSession         0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/user.go:26:            User                    0.0%
      github.com/gogf/gf-demo-user/v2/internal/service/user.go:33:            RegisterUser            0.0%
      total:                                                                  (statements)            0.0%


      真实案例
      被测试的函数
      func Split(s, sub string) (result []string) {
      if len(strings.TrimSpace(s)) == 0 {
      return
      }
      i := strings.Index(s, sub)
      for i > -1 {
      if i == 0 {
      s = s[len(sub):]
      } else {
      result = append(result, s[:i])
      s = s[i+len(sub):]
      }
      i = strings.Index(s, sub)
      }
      result = append(result, s)
      return
      }


      简单的测试
      get := Split("a:b:c", ":")
      wanted := []string{"a", "b", "c"}
      if !reflect.DeepEqual(wanted, get) {
      t.Errorf("expected:%v,get:%v", wanted, get)
      }


      多维度测试案例
      func TestMultiSplit(t *testing.T) {
      type test struct {
      name   string
      input  string
      sub    string
      wanted []string
      }
      tests := []test{
      {name: "正常的测试用例", input: "a:b:c", sub: ":", wanted: []string{"a", "b", "c"}},
      {name: "字符串头位置匹配测试", input: ":a:b:c", sub: ":", wanted: []string{"a", "b", "c"}},
      {name: "无匹配项的测试", input: "abc", sub: ":", wanted: []string{"abc"}},
      {name: "英文串的测试", input: "abcd", sub: "bc", wanted: []string{"a", "d"}},
      {name: "中文串的测试", input: "云原生", sub: "云", wanted: []string{"原生"}},
      }
      for _, d := range tests {
      get := Split(d.input, d.sub)
      if !reflect.DeepEqual(d.wanted, get) {
      t.Errorf("[testName:%v][expected:%v] [get:%v]", d.name, d.wanted, get)
      }
      }
      }


      GoFrame 中依赖框架配置文件的单元测试
      加载测试用例的配置文件
      root.go
      package testingutil

      import (
      "path"
      "runtime"
      )

      func RootDir() string {
      _, d, _, _ := runtime.Caller(0)
      return path.Dir(path.Dir(d))
      }


      root_test.go
      package testingutil

      import "testing"

      func TestRootDir(t *testing.T) {
      rootDir := RootDir()
      t.Log(rootDir)
      }

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


      初始化加载GoFrame配置环境
      config.go
      package testingutil

      import (
      "github.com/gogf/gf/v2/os/genv"
      "path"
      )

      func init() {
      InitConfig()
      }

      func InitConfig() {
      configDir := path.Join(RootDir(), "manifest/config")

      genv.Set("GF_GCFG_PATH", configDir)
      }


      引入环境,并编写mysql、redis的测试用例
      func TestMysql(t *testing.T) {
      testingutil.InitConfig()
      ctx := gctx.New()
      countSql := "select collection_id,count(1) as count from transfer_logs" + " where 1 = 1" + " " + " group by collection_id"

      var countList []struct {
      CollectionId int64 `json:"collection_id"`
      Count        int   `json:"count"`
      }

      // 获取内容
      all, err := g.DB().Ctx(ctx).GetAll(ctx, countSql)
      if err != nil {
      t.Fatal(err)
      }
      all.Structs(&countList)
      fmt.Printf("%+v", countList)
      }

      func TestRedis(t *testing.T) {
      testingutil.InitConfig()
      ctx := gctx.New()
      cache := gcache.NewAdapterRedis(g.Redis())
      err := cache.Set(ctx, 1, 1, time.Second*10)
      if err != nil {
      t.Fatal(err)
      }
      }



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

    使用道具 举报

    本版积分规则

    关闭

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

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

    GMT+8, 2024-11-25 06:10 , Processed in 0.067023 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

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