编写可测试的better go代码示例分析

发布时间:2022-01-17 16:55:40 作者:柒染
来源:亿速云 阅读:116

今天给大家介绍一下编写可测试的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代码示例分析相关的内容可以搜索亿速云之前的文章或者浏览下面的文章进行学习哈!相信小编会给大家增添更多知识,希望大家能够支持一下亿速云!

推荐阅读:
  1. go语言中rune的介绍和使用
  2. golang碎片整理之fmt.Scan的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

go

上一篇:Oracle数据库JOB失败怎么解决

下一篇:Java怎么实现创建Zip压缩包并写入文件

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》