今天给大家介绍一下编写可测试的better go代码示例分析。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。
在开发一个接口的时候,通常要引入数据库、redis、或者内部调用其他服务,单元测试需要先将对应的数据库、redis、第三方服务都启动,不然,没法做单元测试。 下面就是解决这种情况,原则上认为底层相关服务都已经经过了严格的单元测试,所以将相关的方法提取出来,在单元测试的时候,模拟替换实际的数据库、redis、或其他内部的服务。
一个普通的例子
下面启动了一个http服务,对外提供一个/bad接口,这个接口的功能就是接收一个string类型的参数 args,并通过db查询出apps
//better/main.go
package main
import (
"errors"
"net/http"
"better/service"
"github.com/jinzhu/gorm"
)
func main() {
http.HandleFunc("/bad", func(w http.ResponseWriter, r *http.Request) {
args := r.URL.Query().Get("args")
//init db
db, err := dao.NewStorage()
if err != nil {
w.Write([]byte(err.Error()))
w.WriteHeader(http.StatusBadRequest)
return
}
apps, err := service.NewHandle().GetApps(args, db.DB)
if err != nil {
w.Write([]byte(err.Error()))
w.WriteHeader(http.StatusBadRequest)
return
}
w.Write([]byte(apps))
w.WriteHeader(http.StatusOK)
return
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
service层
//better/service/bad.go
package service
import (
"errors"
"github.com/jinzhu/gorm"
)
type handle struct {
}
func NewHandle() *handle {
return &handle{}
}
func (h handle) GetApps(args string, db *gorm.DB) (apps string, err error) {
if args == "" {
return "", errors.New("args is nil")
}
//引入 db
err = db.Find(&apps).Error
if err != nil {
return "", err
}
return apps, nil
}
数据库层
//better/dao/apps.go
package dao
import "github.com/jinzhu/gorm"
type Storage struct {
DB *gorm.DB
}
func NewStorage() (*Storage, error) {
db, err := gorm.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
return nil, err
}
return &Storage{DB: db}, nil
}
func (s *Storage) GetApps() (string, error) {
return "dao apps", nil
}
单元测试代码
//better/service/bad_test.go
package service
import (
"testing"
"github.com/jinzhu/gorm"
)
func Test_GetApps(t *testing.T) {
db, err := gorm.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
t.Fatal("gorm open err", err.Error())
}
_, err = NewHandle().GetApps("test", db)
if err != nil {
t.Fatal("getApps err", err.Error())
}
t.Log("success")
}
如果要针对func (h handle) getApps(args string, db *gorm.DB) (apps string, err error) 这个方法进行单元测试,我们就不得不启动一个mysql,这样单元测试代码就db严重耦合了。如果方法内部还涉及了调用其他服务,我们还得启动其他服务,这样单元测试写起来就非常不方便。
一种更好的实现方式
新增一个better接口
//better/main.go
package main
import (
"net/http"
"better/dao"
"better/service"
"github.com/jinzhu/gorm"
)
func main() {
http.HandleFunc("/better", func(w http.ResponseWriter, r *http.Request) {
args := r.URL.Query().Get("args")
//init db
db, err := dao.NewStorage()
if err != nil {
w.Write([]byte(err.Error()))
w.WriteHeader(http.StatusBadRequest)
return
}
apps, err := service.NewBetterHandle(db).GetApps(args)
if err != nil {
w.Write([]byte(err.Error()))
w.WriteHeader(http.StatusBadRequest)
return
}
w.Write([]byte(apps))
w.WriteHeader(http.StatusOK)
return
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
service层
//better/service/better.go
package service
import "errors"
// better go
type betterHandle struct {
Storage BetterHandleStorage
}
type BetterHandleStorage interface {
GetApps() (string, error)
}
func NewBetterHandle(storage BetterHandleStorage) *betterHandle {
return &betterHandle{Storage: storage}
}
func (h betterHandle) GetApps(args string) (apps string, err error) {
if args == "" {
return "", errors.New("args is nil")
}
apps, err = h.Storage.GetApps()
if err != nil {
return "", err
}
return apps, nil
}
单元测试
package service
import (
"testing"
)
func Test_BetterGetApps(t *testing.T) {
var m DBMock
apps, err := NewBetterHandle(&m).GetApps("Test_BetterGetApps")
if err != nil {
t.Fatal("getApps err", err.Error())
}
t.Log("apps:", apps)
}
type DBMock struct {
}
// 构建mock数据
// 这样我们就可以测试我们的方法,而不需要启动一个db
func (m *DBMock) GetApps() (string, error) {
return "mock apps", nil
}
以上就是编写可测试的better go代码示例分析的全部内容了,更多与编写可测试的better go代码示例分析相关的内容可以搜索天达云之前的文章或者浏览下面的文章进行学习哈!相信小编会给大家增添更多知识,希望大家能够支持一下天达云!