目录

Go Module与测试


Go Module

简介

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包
  • 终极目标
    • 定义版本规则和管理项目依赖关系

依赖管理三要素

  1. 配置文件,描述依赖 go.mod(类比cargo)
  2. 中心仓库管理依赖库 Proxy(类比crates.io)
  3. 本地工具 go get/mod

配置go.mod

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
module example/project/app 依赖管理的基本单元
(有的时候大项目里面的小项目就得则么写类比c++中src下面的CMakeList.txt)
(或者一个大包但是别人只想用里面的小包)

go 1.16 原生库

require( 单元依赖
  example/lib1 v1.0.2
  example/lib2 v1.0.0 //indirect
  example/lib6 v3.2.0+incompatible
  //...
)

依赖配置-version

  • 语义化版本

    • ${MAJOR}.${MINOR}.${PATCH}
      • MAJOR:大版本,不同的MAJOR间认为是代码不兼容的
      • MINOR:新增函数或功能,需要保持MAJOR下的兼容性
      • PATCH:部分bug的修复
    • V1.3.0
    • V2.3.0
  • 基于commit伪版本

    • vX.0.0-yyyymmddhhmmss-abcdefg1234
      • 版本前缀-时间戳-哈希码前缀
      • v0.0.0-20220401081311-c38fb921298
      • v1.0.0-20201130134442-10cb123792679c6c
  • indirtect

  • A -> B:直接依赖

  • A -> C:间接依赖,使用indirtect进行标识

  • incompatible

    • 对于没有go.mod文件而且主版本2+的依赖,会+incompatible
  • 最低兼容算法

/img/Go/Module_and_test.jpg

依赖分发-回源

  • 问题

    • 无法保证构建的稳定性和依赖的可用性
    • 增加第三方压力
  • 解决方法Proxy

  • (类比crates.io),自己构建大仓库保证稳定性

GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"(direct表示源站)

  • 我的配置:GOPROXY=https://proxy.golang.com.cn,direct

工具-go get

  • go get example.org/pkg
    • @update 默认
    • @none 删除依赖
    • @v1.1.2 tag版本,语义版本
    • @23dfdd5 特定的commit
    • @master 分支最新的commit

工具-go mod

  • go mod
    • init 初始化,创建go.mod文件
    • download 下载模块到本地缓存
    • tidy 增加需要的依赖,删除不需要的依赖

总结

  1. go.mod
  2. Proxy
  3. go get/mod

测试

单元测试流程

  • 测试单元
    • 函数
    • 模块

规则

  • 所有测试文件以_test.go结尾(如publish_post_test.go)

  • func TestXxx(*testing.T)(如func TestPublishPost(t *testing.T))

  • 初始化逻辑放到TestMain中

  • 例子publish_post.go

1
2
3
4
5
package main

func HelloTom() string {
     return "Jerry"
}

publish_post_test.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "testing"

func TestMain(t *testing.T) {
     output := HelloTom()
     exceptOutput := "Tom"
     if output != exceptOutput {
      t.Errorf("Expect %v, but output %v", exceptOutput, output)
     }
}

(校对部分建议使用开源的assert包)

  • 执行效果
1
2
3
4
5
6
$ go test
--- FAIL: TestMain (0.00s)
    publish_post_test.go:9: Expect Tom, but output Jerry
FAIL
exit status 1
FAIL    learing_go      0.261s

覆盖率

  • 覆盖度,越高代码的正确性越好

  • 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

func HelloTom() string {
     return "Jerry"
}

func JudgePassLine(score int16) bool {
     if score >= 60 {
      return true
     }
     return false
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import (
     "testing"
)

func TestMain(t *testing.T) {
     output := HelloTom()
     exceptOutput := "Jerry"
     if output != exceptOutput {
      t.Errorf("Expect %v, but output %v", exceptOutput, output)
     }
     isPass := JudgePassLine(70)
     if isPass != true {
      t.Errorf("Expect %v, but output %v", true, isPass)
     }
}
1
2
3
4
$ go test --cover
PASS
coverage: 27.3% of statements
ok      learing_go      0.260s
  • 如果加上修改
1
2
3
func JudgePassLine(score int16) bool {
     return score >= 60
}
1
2
$ go test .\publish_post_test.go .\publish_post.go --cover
ok      command-line-arguments  0.254s  coverage: 100.0% of statements

单元测试-依赖

  • 幂等:每次运行结果一样(应该涉及了并发的问题,暴力测试)

  • 稳定:任何时间,任何函数进行独立运行

  • Mock

基准测试

  • 优化分析代码

  • 内置

  • 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import (
     "math/rand"
)

var ServerIndex [10]int

func InitServerIndex() {
     for i := 0; i < 10; i++ {
      ServerIndex[i] = i + 100
     }
}

func Select() int {
     return ServerIndex[rand.Intn(10)]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
     "testing"
)

func BenchmarkSelect(b *testing.B) {
     InitServerIndex()
     b.ResetTimer()
     for i := 0; i < b.N; i++ {
      Select()
     }
}

func BenchmarkSelectParallel(b *testing.B) {
     InitServerIndex()
     b.ResetTimer()
     b.RunParallel(func(p *testing.PB) {
      for p.Next() {
       Select()
      }
     })
}
1
2
3
4
5
6
7
8
9
Running tool: D:\Go\bin\go.exe test -benchmem -run=^$ -bench ^BenchmarkSelect$ learing_go

goos: windows
goarch: amd64
pkg: learing_go
cpu: AMD Ryzen 9 5900HX with Radeon Graphics        
BenchmarkSelect-16     175706265          6.498 ns/op        0 B/op        0 allocs/op
PASS
ok   learing_go 2.053s
1
2
3
4
5
6
7
8
9
Running tool: D:\Go\bin\go.exe test -benchmem -run=^$ -bench ^BenchmarkSelectParallel$ learing_go

goos: windows
goarch: amd64
pkg: learing_go
cpu: AMD Ryzen 9 5900HX with Radeon Graphics        
BenchmarkSelectParallel-16     30002550         38.89 ns/op        0 B/op        0 allocs/op
PASS
ok   learing_go 1.409s