用Golang流行的web框架Gin渲染HTML模板頁(yè)面的簡(jiǎn)單例子
Gin是Golang最流行的web框架之一。我之前已經(jīng)寫(xiě)過(guò)如何使用Golang基礎(chǔ)模板包渲染HTML頁(yè)面。使用Gin渲染HTML模板更加簡(jiǎn)單。
為了使工作流更加順暢,嘗試新的想法并進(jìn)行調(diào)試,我還決定使用Codegangsta的自動(dòng)重載工具Gin。
安裝Gin HTTP web框架就像安裝大多數(shù)(如果不是所有)Golang包一樣簡(jiǎn)單:
go get -u github.com/gin-gonic/gin
package main
import (
"html/template"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func main() {
router :=gin.Default()
router.SetFuncMap(template.FuncMap{
"upper": strings.ToUpper,
})
router.Static("/assets", "./assets")
router.LoadHTMLGlob("templates/*.html")
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"content": "This is an index page...",
})
})
router.GET("/about", func(c *gin.Context) {
c.HTML(http.StatusOK, "about.html", gin.H{
"content": "This is an about page...",
})
})
router.Run("localhost:8080")
}
在第4到7行,我們引入了一些包:
在第11行,我們創(chuàng)建了一個(gè)名為router的默認(rèn)Gin路由。默認(rèn)的Gin路由使用日志和恢復(fù)中間件,以及基本功能。
在第12到14行,使用SetFuncMap()創(chuàng)建一個(gè)供模板使用的函數(shù)映射。這里我們添加了一個(gè)簡(jiǎn)單的模板函數(shù)upper,它使用strings.ToUpper()函數(shù)將字符串中的所有字符設(shè)置為大寫(xiě)。
在第15行,我們讓Gin路由知道我們?cè)?/span>./assets目錄中保存了一些靜態(tài)資產(chǎn)。Gin可以以這種方式訪問(wèn)任何靜態(tài)資源。
在這個(gè)例子中,我在那個(gè)目錄中放了一個(gè)Bulma CSS庫(kù)的最小版本。通過(guò)使用Static()函數(shù),現(xiàn)在HTML模板可以訪問(wèn)這個(gè)庫(kù)。
在第16行,所有滿(mǎn)足template/*.html模式的模板都由LoadHTMLGlob()函數(shù)加載。這個(gè)模式意味著模板文件應(yīng)該有.html的擴(kuò)展名,并且位于/template目錄中。
在第18到22行,我們告訴Gin路由接受URL路徑/上的HTTP GET方法請(qǐng)求。當(dāng)收到請(qǐng)求時(shí),Gin發(fā)送一個(gè)HTTP OK狀態(tài)消息,并用gin.H{}括號(hào)內(nèi)提供的數(shù)據(jù)渲染index.html模板。在這種情況下,數(shù)據(jù)只包括一個(gè)鍵/值對(duì),鍵名為content。
在第24到28行,與上面類(lèi)似,我們告訴Gin路由接受/about路徑上的HTTP GET方法請(qǐng)求。這次渲染的是about.html模板。
在第29行,我們讓Gin在localhost端口8080上運(yùn)行web服務(wù)器。
下面你可以找到本例中使用的四個(gè)模板。這些模板每個(gè)都需要在自己的文件中。每段代碼之前都有文件名。
模板的語(yǔ)法與html/template基礎(chǔ)包中的相同。你可以我之前的文章中閱讀更多關(guān)于模板語(yǔ)法的內(nèi)容。
// header.html
{{define "header.html"}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/assets/bulma.min.css">
<title></title>
</head>
<body>
<div class="container">
<br><br>
{{end}}
// footer.html
{{define "footer.html"}}
</div>
</body>
</html>
{{end}}
// index.html
{{template "header.html"}}
<h1 class="title">
INDEX PAGE
</h1>
<p>{{ .content }}</p>
{{template "footer.html"}}
// about.html
{{template "header.html"}}
<h1 class="title">
ABOUT PAGE
</h1>
<p>{{ .content | upper}}</p>
{{template "footer.html"}}
如前所述,我在開(kāi)發(fā)時(shí)使用codegangsta/gin工具來(lái)自動(dòng)重載gin。這使得在瀏覽器中檢查我們代碼的結(jié)果變得更加容易。當(dāng)我們改變了代碼,無(wú)需停止當(dāng)前的可執(zhí)行文件,重新構(gòu)建和運(yùn)行它,就可以做到這一點(diǎn)。
以下是Github頁(yè)面上對(duì)這個(gè)工具的描述:
gin是一個(gè)簡(jiǎn)單的命令行工具,用于實(shí)時(shí)重新加載Go web應(yīng)用程序。只需在你的應(yīng)用程序目錄下運(yùn)行gin,你的web應(yīng)用就會(huì)以gin作為代理來(lái)服務(wù)。gin會(huì)在檢測(cè)到更改時(shí)自動(dòng)重新編譯你的代碼。下次它接收到HTTP請(qǐng)求時(shí),你的應(yīng)用將會(huì)重啟。
go get github.com/codegangsta/gin
gin -i --appPort 8080 --port 3000 run main.go
上述代碼需要在命令行中運(yùn)行。它假設(shè)你正在localhost的8080端口上運(yùn)行你的Go web應(yīng)用,并且你將使用3000端口作為Gin自動(dòng)重載代理。
在從命令行運(yùn)行代碼之前,你可能需要運(yùn)行以下命令:
go mod init
go mod tidy
在瀏覽器的URL字段中輸入以下內(nèi)容以檢查代碼的結(jié)果:
localhost:3000/
…對(duì)于索引頁(yè)面,和…
localhost:3000/about
對(duì)于關(guān)于頁(yè)面。
請(qǐng)記住,始終保持學(xué)習(xí)的態(tài)度,并享受編碼的樂(lè)趣!祝您編碼愉快!
如果你喜歡我的文章,點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā)!
在移動(dòng)端平臺(tái)開(kāi)發(fā)中,為了增加代碼復(fù)用,降低開(kāi)發(fā)成本,通常會(huì)需要采用跨平臺(tái)的開(kāi)發(fā)技術(shù),花椒也不例外。本次新的單品開(kāi)發(fā),由于時(shí)間緊,人員有限,經(jīng)過(guò)調(diào)研選型,最終確定了 flutter 方案(具體選型過(guò)程不在本文討論之內(nèi))。
為了讓客戶(hù)端更專(zhuān)注業(yè)務(wù)實(shí)現(xiàn),降低接口聯(lián)調(diào)測(cè)試成本,我們選用了 gRPC 方案。gRPC是一個(gè)高性能、通用的開(kāi)源 RPC 框架,由 Google 開(kāi)發(fā)并基于 HTTP/2 協(xié)議標(biāo)準(zhǔn)而設(shè)計(jì),基于 ProtoBuf(Protocol Buffers)序列化協(xié)議開(kāi)發(fā),且支持當(dāng)前主流開(kāi)發(fā)語(yǔ)言。gRPC通過(guò)定義一個(gè)服務(wù)并指定一個(gè)可以遠(yuǎn)程調(diào)用的帶有參數(shù)和返回類(lèi)型的的方法,使客戶(hù)端可以直接調(diào)用不同機(jī)器上的服務(wù)應(yīng)用的方法,就像是本地對(duì)象一樣。在服務(wù)端,服務(wù)實(shí)現(xiàn)這個(gè)接口并且運(yùn)行 gRPC 服務(wù)處理客戶(hù)端調(diào)用。在客戶(hù)端,有一個(gè)stub提供和服務(wù)端相同的方法。
特點(diǎn)
gRPC-Web 為前端瀏覽器提供了 Javascript 庫(kù)用來(lái)訪問(wèn) gRPC 服務(wù),但是需要通過(guò) Envoy 提供代理服務(wù)。相比 JSON 的方式對(duì)前端不夠友好,同時(shí)也增加了服務(wù)端的部署成本。因此在這次項(xiàng)目中前端未使用 gRPC 服務(wù),而是由 gRPC-Gateway 提供代理的 RESTful 接口。
grpc-gateway 是 protoc 的一個(gè)插件,它能讀取 gRPC 的服務(wù)定義并生成反向代理服務(wù)器,將 RESTful 的 JSON 請(qǐng)求轉(zhuǎn)換為 gRPC 的方式。這樣無(wú)需太多工作即可實(shí)現(xiàn)一套基于 gRPC 服務(wù)的 RESTful 接口,方便前端使用調(diào)用接口,同時(shí)也方便開(kāi)發(fā)過(guò)程中通過(guò) Postman/Paw 之類(lèi)的工具調(diào)試接口。
gateway -> gRPC 映射方式:
例如,gRPC 接口要求的通用的 metadata 參數(shù)(如 platform, device_id 等)在 HTTP RESTful 的傳遞方式如下:
dart
為了便于客戶(hù)端調(diào)用,連接復(fù)用及通用參數(shù)傳遞,我們封裝了 dart 的基礎(chǔ)庫(kù)。
BaseClient 維護(hù)了針對(duì) HOST 緩存的連接池,同時(shí)也提供了接口需要傳遞的 metadata 信息。
golang
golang 后端服務(wù)需要同時(shí)支持 gRPC 和 gateway 兩種請(qǐng)求方式。為了簡(jiǎn)化部署和上線(xiàn)依賴(lài),gateway 和 gRPC 的功能放在了一起,并通過(guò)攔截器注入對(duì)應(yīng)的功能,主要包括 gRPC 統(tǒng)計(jì),訪問(wèn)日志,接口鑒權(quán),請(qǐng)求參數(shù)校驗(yàn),gateway JSON 編碼等。
為了提高開(kāi)發(fā)效率,方便維護(hù)及模塊復(fù)用,服務(wù)端按功能進(jìn)行組件化開(kāi)發(fā)。每個(gè)組件可以單獨(dú)運(yùn)行一個(gè)服務(wù),也可以和其它組件共同組成一個(gè)服務(wù)。每個(gè)組件都需要實(shí)現(xiàn) Component 接口:
對(duì)應(yīng)組件開(kāi)發(fā)完成后,需要開(kāi)發(fā)對(duì)應(yīng)的服務(wù)容器,步驟如下。
1 base.Init(context.TODO(), cfg, &global.Callback{ 2 Authenticator: &auth.Callback{}, 3 LogCapture: &log.Capture{}, 4 })
base.DefaultServer.AddPublicServer(rpcPort, gatewayPort, setting.TLSConfig)
1 base.DefaultServer.RegisterComponent(&user.Component{}) 2 base.DefaultServer.RegisterComponent(&push.Component{}) 3 ...
base.DefaultServer.Serve()
proto 規(guī)范
gRPC 基于標(biāo)準(zhǔn)化的 IDL(ProtoBuf)來(lái)生成服務(wù)器端和客戶(hù)端代碼,我們決定將所有的接口描述及文檔說(shuō)明都放到 proto 文件中,便于查看及修改。對(duì) proto 的接口描述及注釋的規(guī)范如下:
代碼生成
golang
1 gengo: 2 @protoc -Iproto \ 3 -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ 4 -I${GOPATH}/src/github.com/lnnujxxy/protoc-gen-validate \ 5 -I${GOPATH}/src/github.com/youlu-cn/grpc-gen/protoc-gen-auth \ 6 --go_out=plugins=grpc:go/pb \ 7 --grpc-gateway_out=logtostderr=true:go/pb \ 8 --validate_out="lang=go:go/pb" \ 9 --auth_out="lang=go:go/pb" \ 10 proto/*.proto
golang 使用 go mod 的方式直接引入 pb 生成的 .go 文件
dart
修改 pubspec.yaml,執(zhí)行 flutter packages get 或 flutter packages upgrade
1 dependencies: 2 flutter: 3 sdk: flutter 4 5 protobuf: ^0.13.4 6 grpc: ^1.0.1 7 user: 8 git: 9 url: git@github.com:project/repo.git 10 path: dart/user
gRPC gateway 提供了通過(guò) proto 文件生成 swagger API 文檔,缺點(diǎn)是只支持 gateway 的 RESTful 接口,并且默認(rèn)的展示方式有點(diǎn)不符合我們的常規(guī)文檔使用方式。
我們基于 protoc 插件開(kāi)發(fā)了 protoc-gen-markdown 工具,可以由 proto 文件生成 markdown 文檔,提供 gRPC 接口描述,以及 RESTful 接口描述及 JSON 示例,提供全文目錄,支持錨點(diǎn)導(dǎo)航等。生成方式如下:
1gendoc: 2 @protoc -Iproto \ 3 -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ 4 -I${GOPATH}/src/github.com/lnnujxxy/protoc-gen-validate \ 5 -I${GOPATH}/src/github.com/youlu-cn/grpc-gen/protoc-gen-auth \ 6 --markdown_out=":doc" \ 7 proto/*.proto
文檔會(huì)在對(duì)應(yīng)路徑生成接口列表 README.md,以及每個(gè) protobuf 對(duì)應(yīng)的接口文檔。
傳統(tǒng)的 RESTful 接口在調(diào)試及問(wèn)題排查時(shí),可以通過(guò)抓包或者 MitM(中間人攻擊)的方式,配置也比較容易。而 gRPC 因?yàn)槭褂昧?HTTP2 及 protobuf 二進(jìn)制流,抓包及數(shù)據(jù)流反解難度相對(duì)較高,調(diào)試及問(wèn)題排查時(shí)會(huì)比較復(fù)雜。為了解決這個(gè)問(wèn)題,我們通過(guò)服務(wù)端注入的方式,配合查詢(xún)后臺(tái)過(guò)濾對(duì)應(yīng)的請(qǐng)求日志,從而實(shí)現(xiàn)如下類(lèi)似抓包的效果。
Go語(yǔ)言中文網(wǎng),致力于每日分享編碼、開(kāi)源等知識(shí),歡迎關(guān)注我,會(huì)有意想不到的收獲!
本文由花椒服務(wù)端團(tuán)隊(duì)原創(chuàng)授權(quán)發(fā)布
近在給項(xiàng)目代碼完善單元測(cè)試,發(fā)現(xiàn)go語(yǔ)言單元測(cè)試相關(guān)的資料都是零零散散的,所以在這兒整理總結(jié)一下。項(xiàng)目中使用的是goconvey+monkey+sqlmock (項(xiàng)目的web框架為gin, 持久層框架為gorm), 使用時(shí)也碰到一些坑,也會(huì)在這篇文章中做一些相關(guān)的記錄。 文章大約4200字,囿于篇幅,很多地方都是一筆帶過(guò),不過(guò)在每一部分之后提供了一些筆者讀過(guò)覺(jué)得不錯(cuò)的資料的鏈接,大家可以根據(jù)需要查看。
1.1 testing——Go內(nèi)置的單元測(cè)試庫(kù)。
要編寫(xiě)一個(gè)新的測(cè)試,需要?jiǎng)?chuàng)建一個(gè)以 _test.go 結(jié)尾的文件,該文件包含 TestXxx 函數(shù)。 將該文件放在與被測(cè)試的包相同的包中。
通過(guò) go test 命令,能夠自動(dòng)執(zhí)行如下形式的任何函數(shù):
func TestXxx(*testing.T)
注意:Xxx 可以是任何字母數(shù)字字符串,但是第一個(gè)字母不能是小寫(xiě)字母(一般接被測(cè)試函數(shù)名字,不強(qiáng)求)。傳遞給測(cè)試函數(shù)的參數(shù)是 *testing.T 類(lèi)型。它用于管理測(cè)試狀態(tài)并支持格式化測(cè)試日志。測(cè)試日志會(huì)在執(zhí)行測(cè)試的過(guò)程中不斷累積,并在測(cè)試完成時(shí)轉(zhuǎn)儲(chǔ)至標(biāo)準(zhǔn)輸出。
詳情參見(jiàn):The-Golang-Standard-Library-by-Example
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter09/09.1.html
1.2 TestMain
在寫(xiě)測(cè)試時(shí),有時(shí)需要在測(cè)試之前或之后進(jìn)行額外的設(shè)置(setup)或拆卸(teardown);有時(shí),測(cè)試還需要控制在主線(xiàn)程上運(yùn)行的代碼。為了支持這些需求,testing 提供了 TestMain 函數(shù):
func TestMain(m *testing.M)
如果測(cè)試文件中包含該函數(shù),那么生成的測(cè)試將調(diào)用 TestMain(m),而不是直接運(yùn)行測(cè)試。
TestMain 運(yùn)行在主 goroutine 中, 可以在調(diào)用 m.Run 前后做任何設(shè)置和拆卸。注意,在 TestMain 函數(shù)的最后,應(yīng)該使用 m.Run 的返回值作為參數(shù)調(diào)用 os.Exit。
詳情參見(jiàn):TestMain
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter09/09.5.html#testmain
1.3 httptest——HTTP測(cè)試輔助工具
Go 標(biāo)準(zhǔn)庫(kù)專(zhuān)門(mén)提供了 httptest 包專(zhuān)門(mén)用于進(jìn)行 http Web 開(kāi)發(fā)測(cè)試。
httptest包最關(guān)鍵的是提供了一個(gè) http.ReponseWriter接口的實(shí)現(xiàn)結(jié)構(gòu):httptest.ReponseRecorder,通過(guò)它可以得到一個(gè)http.ReponseWriter,并以此來(lái)接收服務(wù)器返回的響應(yīng)包。
詳情參見(jiàn):httptest - HTTP 測(cè)試輔助工具
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter09/09.6.html
1.4 測(cè)試覆蓋率
Go 從 1.2 開(kāi)始,引入了測(cè)試覆蓋率的支持,使用的是 cover 相關(guān)的工具(go test -cover、go tool cover)。
詳情參見(jiàn):The cover story
https://blog.golang.org/cover
Go標(biāo)準(zhǔn)包里并沒(méi)有斷言庫(kù),但是不使用斷言庫(kù)進(jìn)行結(jié)果校驗(yàn)的話(huà),測(cè)試代碼將會(huì)變得非常臃腫,可讀性和可維護(hù)性都會(huì)很差。不過(guò)好在有第三方框架可以讓我們使用。
2.1 testify
github地址:https://github.com/stretchr/testify
特性:
2.2 gocheck
godoc地址:https://godoc.org/gopkg.in/check.v1
特性:
詳情參見(jiàn):gocheck 使用介紹
https://zhuanlan.zhihu.com/p/45570168
2.3 goconvey
github地址: https://github.com/smartystreets/goconvey
特性:
詳情參見(jiàn):GoConvey框架使用指南
https://www.jianshu.com/p/e3b2b1194830
2.4 比較
其實(shí)gocheck我沒(méi)怎么用過(guò),只是當(dāng)時(shí)調(diào)研的時(shí)候看到了,在斷言方面看起來(lái)和其他的差不多。
testify和goconvey都有嘗試,最后采用的是goconvey,所以對(duì)goconvey更熟悉一點(diǎn)。
3.1 識(shí)別依賴(lài)
普遍來(lái)說(shuō),我們遇到最常見(jiàn)的依賴(lài)無(wú)非下面幾種:
3.2 mock和stub的區(qū)別
這個(gè)話(huà)題也算是老生常談了。幾句話(huà)很難解釋清楚,有興趣可以閱讀Martin Fowler的文章。
stub本質(zhì)上是對(duì)真實(shí)對(duì)象的一個(gè)模擬,比如調(diào)用者需要一個(gè)值,那就讓stub輸出一個(gè)值,如果調(diào)用者需要傳遞一個(gè)值給stub,那就在stub中定義一個(gè)方法接受該參數(shù),相當(dāng)于“依賴(lài)部分”的一個(gè)簡(jiǎn)化實(shí)現(xiàn)。mock則是在程序代碼中向被測(cè)試代碼注入“依賴(lài)部分”,模擬出函數(shù)調(diào)用返回的結(jié)果。
個(gè)人認(rèn)為兩者最大的區(qū)別在于依賴(lài)對(duì)象是否和被測(cè)對(duì)象有交互,從結(jié)果來(lái)看,stub不會(huì)使測(cè)試失敗,它只是為被測(cè)對(duì)象提供依賴(lài)的對(duì)象,并不改變測(cè)試結(jié)果,而mock則會(huì)根據(jù)不同的交互測(cè)試要求,很可能會(huì)更改測(cè)試的結(jié)果。stub是state-based,關(guān)注的是輸入和輸出。mock是interaction-based,關(guān)注的是交互過(guò)程。
mock和stub還有一個(gè)重要的區(qū)別就是expectiation。對(duì)于mock來(lái)說(shuō),expectiation是重中之重:我們期待方法有沒(méi)有被調(diào)用,期待適當(dāng)?shù)膮?shù),期待調(diào)用的次數(shù),甚至期待多個(gè)mock之間的調(diào)用順序。所有的一切期待都是事先準(zhǔn)備好,在測(cè)試過(guò)程中和測(cè)試結(jié)束后驗(yàn)證是否和預(yù)期的一致。而對(duì)于stub,通常都不會(huì)關(guān)注expectiation,沒(méi)有任何代碼來(lái)幫助判斷這個(gè)stub類(lèi)是否被調(diào)用。雖然理論上某些stub實(shí)現(xiàn)也可以通過(guò)自己編碼的方式增加對(duì)expectiation的內(nèi)容,比如增加一個(gè)計(jì)數(shù)器,每次調(diào)用+1之類(lèi),但是實(shí)際上極少這樣做。
在Go中,如果要用stub,那將是侵入式的,必須將代碼設(shè)計(jì)成可以用stub方法替換的形式。為了測(cè)試,需要專(zhuān)門(mén)用一個(gè)全局變量 來(lái)保存具有外部依賴(lài)的方法。然而在不提倡使用全局變量的Go語(yǔ)言當(dāng)中,這顯然是不合適的。所以,并不提倡這種Stub方式。
但其實(shí)這兩種方法并不是割裂的,例如像下文提到的gomock框架除了像其名字一樣可以mock對(duì)象以外,還提供了stub的功能。軟件工程沒(méi)有銀彈,我們需要根據(jù)合適的場(chǎng)景選用合適的方法,甚至可以結(jié)合多種方法使用。
詳情參見(jiàn):Mocks Aren't Stubs(Martin Fowler)
https://martinfowler.com/articles/mocksArentStubs.html
以及 中文翻譯
https://www.cnblogs.com/anf/archive/2006/03/27/360248.html
3.3 gostub
github地址:https://github.com/prashantv/gostub
特性:
缺陷:
詳情參見(jiàn):GoStub框架使用指南
3.4 gomock
github地址:https://github.com/golang/mock
特性:
缺陷:
詳情參見(jiàn):使用Golang的官方mock工具—gomock
https://www.jianshu.com/p/598a11bbdafb
和 GoMock框架使用指南
https://www.jianshu.com/p/f4e773a1b11f
3.5 gomonkey
github地址:https://github.com/bouk/monkey
特性:
缺陷:
詳情參見(jiàn):Monkey框架使用指南
https://www.jianshu.com/p/2f675d5e334e
3.6 sqlmock
github地址: https://github.com/DATA-DOG/go-sqlmock
特性:
缺陷:
3.7 httpexpect
github地址:https://github.com/gavv/httpexpect
特性:
sqlmock和httpexpect都蠻簡(jiǎn)單的,看完github主頁(yè)的QuickStart基本就會(huì)用了~~
4.1 選擇原因
newDB=MysqlDB.ModelTable(c, &Basexxx{}, c.AppID()).Where("type=?", libType).Limit(limit).Offset(offset).Order("created_at desc").Find(&libxxxs)
4.2 gorm+sqlmock使用方法
初始化sqlmock后,然后使用dialect和dsn打開(kāi)一個(gè)新的gorm連接并賦值給數(shù)據(jù)庫(kù)操作實(shí)例
_, mock, _=sqlmock.NewWithDSN("sqlmock_db") MysqlDB.DB, _=gorm.Open("sqlmock", "sqlmock_db")
接下來(lái)就和sqlmock的普通使用沒(méi)什么區(qū)別了,只要mock時(shí)能夠成功的匹配gorm生成的sql語(yǔ)句即可
詳情參見(jiàn):Stub database connection with GORM
https://blog.valletta.io/blog/2018-07-05-stub-database-connection-with-gorm/
4.3 踩坑記錄(持續(xù)更新~)
func A(arg string) error { return B(arg) }
原因:
在不改動(dòng)原有代碼的情況下,有2種解決方案:
5.1 單元測(cè)試的粒度
對(duì)于剛開(kāi)始做單元測(cè)試的同學(xué)來(lái)說(shuō),如何把握單元測(cè)試的粒度是一個(gè)讓人頭疼的問(wèn)題。
測(cè)試粒度做的太細(xì),會(huì)耗費(fèi)大量的開(kāi)發(fā)以及維護(hù)時(shí)間,每改一個(gè)方法,都要改動(dòng)其對(duì)應(yīng)的測(cè)試方法。當(dāng)發(fā)生代碼重構(gòu)的時(shí)候那簡(jiǎn)直就是噩夢(mèng)(因?yàn)樗械膯卧獪y(cè)試又都要寫(xiě)一遍了…)。
如果單元測(cè)試粒度太粗,一個(gè)測(cè)試方法測(cè)試了n多方法,那么單元測(cè)試將顯的非常臃腫,脫離了單元測(cè)試的本意,容易把單元測(cè)試寫(xiě)成集成測(cè)試。
5.2 單元測(cè)試的成本和收益
在受益于單元測(cè)試的好處的同時(shí),也必然增加了代碼量以及維護(hù)成本。
下面這張成本/價(jià)值象限圖清晰闡述了在不同性質(zhì)的系統(tǒng)中單元測(cè)試的成本和價(jià)值之間的關(guān)系。
參考鏈接
下面是一些其他的參考資料:
1. The-Golang-Standard-Library-by-Example
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/
2. 搞定Go單元測(cè)試(一)——基礎(chǔ)原理
https://juejin.im/post/5ce93447e51d45775746b8b0#heading-12
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。