Go语言工程实践之测试 | 青训营笔记

147 阅读1分钟

三、Go 语言工程实践之测试

1、测试

  • 回归测试
  • 集成测试
  • 单元测试

从上到下,覆盖率逐层变大,成本逐层降低

1.1 单元测试-规则

  • 所以测试文件以_test.go结尾
  • func TestXxx(*testing.T)
  • 初始化逻辑放到TestMain

1.2 单元测试-覆盖率

--cover

Tips:

  • 一般覆盖率:50%~60%,较高覆盖率80%+
  • 测试分支相互独立,全面覆盖
  • 测试单元粒度足够小,函数单一职责

1.3、单元测试-依赖

外部依赖 =>稳定&幂等

1.4、单元测试-Mock

monkey :github.com/bouk/monkey

Mock函数 不强依赖本地文件

  • 为一个函数打桩
  • 为一个方法打桩

1.5基准测试

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试的能力
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(pb *testing.PB) {
		for pb.Next() {
			Select()
		}
	})
}

image.png

二、项目实战

2.1、需求描述

社区话题页面

  • 展示话题(标题,文字描述)和回帖列表
  • 暂不考虑前端页面的实现,仅仅实现一个本地web服务
  • 话题和回帖数据用文件存储

2.1.1 结构

Topic 话题

  • id
  • title
  • content
  • create_time

Post 帖子

  • id
  • topic_id
  • content
  • create_time

2.2 分层结构

  • 数据层:数据Model,外部数据的增删改查
  • 逻辑层:业务Entity,处理核心业务的逻辑输出
  • 视图层:视图view,处理和外部的交互逻辑

2.3、组件工具

  • Gin高性能go web框架

github.com/gin-gonic/g…

  • Go Mod

go mod init

go get gopkg.in/gin-gonic/gin.v1@v1.3.0

2.4 Repository_index

元数据数据行映射为Map实现内存索引

var (
	topicIndexMap map[int64]*Topic
	postIndexMap  map[int64][]*Post
)

2.5 Service 实体:

type PageInfo struct {
	Topic    *repository.Topic
	PostList []*repository.Post
}
func (f *QueryPageInfoFlow) prepareInfo() error {
	//获取topic信息
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		topic := repository.NewTopicDaoInstance().QueryTopicById(f.topicId)
		f.topic = topic
	}()
	//获取post列表
	go func() {
		defer wg.Done()
		posts := repository.NewPostDaoInstance().QueryPostsByParentId(f.topicId)
		f.posts = posts
	}()
	wg.Wait()
	return nil
}

流程: 参数校验->准备数据->组装实体

2.6 Controller

  • 构建View对象
  • 业务错误码
func QueryPageInfo(topicIdStr string) *PageData {
	topicId, err := strconv.ParseInt(topicIdStr, 10, 64)
	if err != nil {
		return &PageData{
			Code: -1,
			Msg:  err.Error(),
		}
	}
	pageInfo, err := service.QueryPageInfo(topicId)
	if err != nil {
		return &PageData{
			Code: -1,
			Msg:  err.Error(),
		}
	}
	return &PageData{
		Code: 0,
		Msg:  "success",
		Data: pageInfo,
	}

}

2.7 Router

  • 初始化数据索引
  • 初始化引擎配置
  • 构建路由
  • 启动服务
func main() {
	if err := Init("./data/"); err != nil {
		os.Exit(-1)
	}
	r := gin.Default()
	r.GET("/community/page/get/:id", func(c *gin.Context) {
		topicId := c.Param("id")
		data := cotroller.QueryPageInfo(topicId)
		c.JSON(200, data)
	})
	err := r.Run()
	if err != nil {
		return
	}
}