溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

編寫可測(cè)試的better go代碼示例分析

發(fā)布時(shí)間:2022-01-17 16:55:40 來(lái)源:億速云 閱讀:126 作者:柒染 欄目:大數(shù)據(jù)

今天給大家介紹一下編寫可測(cè)試的better go代碼示例分析。文章的內(nèi)容小編覺(jué)得不錯(cuò),現(xiàn)在給大家分享一下,覺(jué)得有需要的朋友可以了解一下,希望對(duì)大家有所幫助,下面跟著小編的思路一起來(lái)閱讀吧。

在開(kāi)發(fā)一個(gè)接口的時(shí)候,通常要引入數(shù)據(jù)庫(kù)、redis、或者內(nèi)部調(diào)用其他服務(wù),單元測(cè)試需要先將對(duì)應(yīng)的數(shù)據(jù)庫(kù)、redis、第三方服務(wù)都啟動(dòng),不然,沒(méi)法做單元測(cè)試。 下面就是解決這種情況,原則上認(rèn)為底層相關(guān)服務(wù)都已經(jīng)經(jīng)過(guò)了嚴(yán)格的單元測(cè)試,所以將相關(guān)的方法提取出來(lái),在單元測(cè)試的時(shí)候,模擬替換實(shí)際的數(shù)據(jù)庫(kù)、redis、或其他內(nèi)部的服務(wù)。

一個(gè)普通的例子

下面啟動(dòng)了一個(gè)http服務(wù),對(duì)外提供一個(gè)/bad接口,這個(gè)接口的功能就是接收一個(gè)string類型的參數(shù) args,并通過(guò)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
}

數(shù)據(jù)庫(kù)層

//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
}

單元測(cè)試代碼

//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")
}

如果要針對(duì)func (h handle) getApps(args string, db *gorm.DB) (apps string, err error) 這個(gè)方法進(jìn)行單元測(cè)試,我們就不得不啟動(dòng)一個(gè)mysql,這樣單元測(cè)試代碼就db嚴(yán)重耦合了。如果方法內(nèi)部還涉及了調(diào)用其他服務(wù),我們還得啟動(dòng)其他服務(wù),這樣單元測(cè)試寫起來(lái)就非常不方便。

一種更好的實(shí)現(xiàn)方式

新增一個(gè)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
}

單元測(cè)試

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 {
}

// 構(gòu)建mock數(shù)據(jù)
// 這樣我們就可以測(cè)試我們的方法,而不需要啟動(dòng)一個(gè)db
func (m *DBMock) GetApps() (string, error) {
    return "mock apps", nil
}

以上就是編寫可測(cè)試的better go代碼示例分析的全部?jī)?nèi)容了,更多與編寫可測(cè)試的better go代碼示例分析相關(guān)的內(nèi)容可以搜索億速云之前的文章或者瀏覽下面的文章進(jìn)行學(xué)習(xí)哈!相信小編會(huì)給大家增添更多知識(shí),希望大家能夠支持一下億速云!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

go
AI