亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Golang中g(shù)omock的使用場(chǎng)景和方法

 更新時(shí)間:2024年10月30日 08:19:22   作者:又落雨噶  
gomock是Go編程語言的模擬框架, 它與Go的內(nèi)置測(cè)試包很好地集成在一起,但也可以在其他上下文中使用,本文主要介紹了gomock的使用場(chǎng)景和方法,感興趣的可以了解下

可惜的是 2023年6月官方停止維護(hù)了,但是我們依舊可以使用 uber 團(tuán)隊(duì)維護(hù)的分支,gomock 依舊是 go 測(cè)試中非常值得學(xué)習(xí)的框架。

介紹

gomock 主要的作用是幫助我們模擬復(fù)雜的函數(shù)和對(duì)象,例如外部接口/RPC調(diào)用/數(shù)據(jù)庫連接/文件操作,當(dāng)然,除了 gomock 社區(qū)還有非常多的其他 mock 框架,例如針對(duì)數(shù)據(jù)庫這類的復(fù)雜對(duì)象進(jìn)行 mock ,總的來說mock類型的框架目的就是 為了幫助我們模擬復(fù)雜對(duì)象的行為,減少我們手動(dòng)創(chuàng)建這些模擬對(duì)象的額外負(fù)擔(dān)。

配合 gomock 的還有 mockgen 工具,用來輔助我們生成測(cè)試代碼,下面介紹如何安裝和使用它們。

安裝

go get -u github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen@v1.6.0

安裝完成后終端驗(yàn)證 mockgen -version 輸出如下:

mockgen -version
v1.6.0

mockgen

安裝完成 mockgen 之后,我們可以簡(jiǎn)單了解一下它支持那些操作,以及常用的 option,終端輸入 mockgen了解相關(guān)的信息:

  • mockgen 有兩種運(yùn)行模式:源模式和反射模式
  • 源模式是從源文件中生成 mock 接口,使用 -source 來啟用源模式,除此之外還可以配合使用 -imports 和 -aux_files 等參數(shù)。
  • 反射模式通過反射來實(shí)現(xiàn)一個(gè)接口的模擬,需要傳入導(dǎo)入的路徑和一個(gè)逗號(hào)分割的參數(shù)列表來創(chuàng)建。

以下是 Gomock 的一般使用步驟:

  • 定義接口:首先,您需要定義一個(gè)要模擬的接口。

  • 生成模擬代碼:在包含接口定義的包目錄下,運(yùn)行 gomock 命令來生成模擬代碼。例如:gomock --package=your_package_name

    • --package :指定生成的模擬代碼所在的包名。
    • --write_package_comment :在生成的代碼中添加包注釋。
    • --self_package :指定生成的模擬對(duì)象屬于當(dāng)前包。
    • --output :指定生成模擬代碼的輸出文件路徑。

代碼示例

首先聲明接口,在 main.go 文件中創(chuàng)建一個(gè)接口,同時(shí)借助 go:generate 來幫助我們自動(dòng)生成相關(guān)的代碼:

//go:generate mockgen -destination=./mock_human.go -package=main -source=main.go
type Human interface {
    Say(str string) string
}

執(zhí)行:go generate ./... 之后,會(huì)在當(dāng)前文件夾下生成一個(gè) mock_human.go 文件,下面我們編寫測(cè)試文件 main_test.go,添加測(cè)試用例。

func Test_mock_human(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()
    mockHuman := NewMockHuman(ctrl)
    mockHuman.EXPECT().Say("test").Return("test")
    if mockHuman.Say("test") != "test" {
       t.Errorf("say fail")
    }
}

執(zhí)行測(cè)試,輸出如下:

=== RUN   Test_mock_human
--- PASS: Test_mock_human (0.00s)
PASS

上面的例子我們僅僅是做演示,方法中用到的方法下面做一下說明,同時(shí)將其他常用的方法也做一下說明。

func Test_mock_human(t *testing.T) {
    t.Run("指定方法的參數(shù)和返回值", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 設(shè)置方法的入?yún)⒑头祷刂?
       mockHuman.EXPECT().Say("test").Return("test result")
       if mockHuman.Say("test") != "test result" {
          t.Errorf("say fail")
       }
    })
    t.Run("EXPECT斷言方法被調(diào)用", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // EXPECT() 方法會(huì)斷言方法被調(diào)用一次
       mockHuman.EXPECT().Say("run 1 times").Return("run 1 times result")
       // 如果不使用指定參數(shù)調(diào)用方法,會(huì)報(bào)錯(cuò):aborting test due to missing call(s)
       if ret := mockHuman.Say("run 1 times"); ret != "run 1 times result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定方法的調(diào)用次數(shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       mockHuman.EXPECT().Say("run 2 times").Return("run 2 times result").Times(2)
       if ret := mockHuman.Say("run 2 times"); ret != "run 2 times result" {
          t.Errorf("say fail:%v", ret)
       }
       if ret := mockHuman.Say("run 2 times"); ret != "run 2 times result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("不指定方法的調(diào)用次數(shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 可以調(diào)用mock方法任意此處(包含0次)
       mockHuman.EXPECT().Say("run any times").Return("run any times result").AnyTimes()
    })
    t.Run("指定方法的最少調(diào)用次數(shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 至少調(diào)用mock方法若干次
       mockHuman.EXPECT().Say("min times").Return("min times result").MinTimes(1)
       if ret := mockHuman.Say("min times"); ret != "min times result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定方法的最多調(diào)用次數(shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 至多調(diào)用mock方法若干次
       mockHuman.EXPECT().Say("max times").Return("max times result").MaxTimes(1)
       if ret := mockHuman.Say("max times"); ret != "max times result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定方法的實(shí)現(xiàn)細(xì)節(jié)-DoAndReturn", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 覆蓋方法的實(shí)現(xiàn),自定義方法的mock實(shí)現(xiàn)
       mockHuman.EXPECT().Say("do and return").DoAndReturn(func(str string) string {
          return "custom return content"
       })
       if ret := mockHuman.Say("do and return"); ret != "custom return content" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定方法的實(shí)現(xiàn)細(xì)節(jié)-Do", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 覆蓋方法的實(shí)現(xiàn),自定義方法的mock實(shí)現(xiàn)
       mockHuman.EXPECT().Say("do and return").Do(func(s string) {
          fmt.Printf("重新實(shí)現(xiàn)方法,%s", s)
       }).Return("custom return content")
       if ret := mockHuman.Say("do and return"); ret != "custom return content" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("不指定具體參數(shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 這里表示無論傳入什么字符串
       mockHuman.EXPECT().Say(gomock.Any()).Return("any arg is okay2").AnyTimes()
       if ret := mockHuman.Say("1"); ret != "any arg is okay2" {
          t.Errorf("say fail:%v", ret)
       }
       if ret := mockHuman.Say("2"); ret != "any arg is okay2" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定傳入?yún)?shù)", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 這里表示參數(shù)必須傳入什么字符串
       mockHuman.EXPECT().Say(gomock.Eq("valid string")).Return("valid result")
       if ret := mockHuman.Say("valid string"); ret != "valid result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定傳入?yún)?shù)不是某一個(gè)具體值", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 這里表示傳入的參數(shù)不能是 valid string
       mockHuman.EXPECT().Say(gomock.Not("valid string")).Return("valid result")
       if ret := mockHuman.Say("invalid string"); ret != "valid result" {
          t.Errorf("say fail:%v", ret)
       }
    })
    t.Run("指定傳入?yún)?shù)是nil", func(t *testing.T) {
       ctrl := gomock.NewController(t)
       defer ctrl.Finish()
       mockHuman := NewMockHuman(ctrl)
       // 這里表示傳入的參數(shù)必須是nil
       mockHuman.EXPECT().Say2(gomock.Nil()).Return("valid result")
       if ret := mockHuman.Say2(nil); ret != "valid result" {
          t.Errorf("say fail:%v", ret)
       }
    })
}

涉及到的方法和方法的作用:

  • EXPECT:用于設(shè)置對(duì)模擬對(duì)象方法調(diào)用的期望,可以定義模擬方法在被調(diào)用時(shí)的各種期望行為,例如期望的調(diào)用次數(shù)、傳入的參數(shù)、返回的值以及可能的副作用操作
  • Times:用于指定期望的方法調(diào)用次數(shù)。
  • AnyTimes:表示模擬的方法可以被調(diào)用任意次數(shù),包括 0 次。
  • MinTimes:指定模擬方法被調(diào)用的最小次數(shù)。
  • MaxTimes:指定模擬方法被調(diào)用的最大次數(shù)。
  • Do:模擬方法被調(diào)用時(shí)執(zhí)行一個(gè)自定義的函數(shù),這個(gè)函數(shù)可以包含一些額外的邏輯或副作用。
  • DoAndReturn:與 Do 類似,但同時(shí)還能指定返回值。
  • Eq:用于驗(yàn)證傳入模擬方法的參數(shù)是否與指定的值相等。
  • Not: 常與其他匹配器結(jié)合使用,用于表示相反的條件。
  • Nil:用于檢查某個(gè)值是否為 nil 。

以上就是 gomock 的使用方法和一些概念。

到此這篇關(guān)于詳解Golang中g(shù)omock的使用場(chǎng)景和方法的文章就介紹到這了,更多相關(guān)Go gomock內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Go語言如何解析帶注釋的json

    詳解Go語言如何解析帶注釋的json

    標(biāo)準(zhǔn)的json格式是不帶注釋,但是有時(shí)候?yàn)榱朔奖憷斫鈐son中各字段的含義,需要支持帶注釋的json,這篇文章主要介紹了Go語言解析帶注釋json的相關(guān)方法,希望對(duì)大家有所幫助
    2024-03-03
  • Go語言Time包的具體使用

    Go語言Time包的具體使用

    Go語言中有關(guān)于時(shí)間和日期的方法都在time包里面,本文主要介紹了Go語言Time包,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • 一文帶你了解Go語言中的I/O接口設(shè)計(jì)

    一文帶你了解Go語言中的I/O接口設(shè)計(jì)

    I/O?操作在編程中扮演著至關(guān)重要的角色,它涉及程序與外部世界之間的數(shù)據(jù)交換,下面我們就來簡(jiǎn)單了解一下Go語言中的?I/O?接口設(shè)計(jì)吧
    2023-06-06
  • 以alpine作為基礎(chǔ)鏡像構(gòu)建Golang可執(zhí)行程序操作

    以alpine作為基礎(chǔ)鏡像構(gòu)建Golang可執(zhí)行程序操作

    這篇文章主要介紹了以alpine作為基礎(chǔ)鏡像構(gòu)建Golang可執(zhí)行程序操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言實(shí)現(xiàn)定時(shí)器的原理及使用詳解

    Go語言實(shí)現(xiàn)定時(shí)器的原理及使用詳解

    這篇文章主要為大家詳細(xì)介紹了Go語言實(shí)現(xiàn)定時(shí)器的兩種方法:一次性定時(shí)器(Timer)和周期性定時(shí)器(Ticker),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • 關(guān)于Go你不得不知道的一些實(shí)用小技巧

    關(guān)于Go你不得不知道的一些實(shí)用小技巧

    開發(fā)語言上Go成為高并發(fā)業(yè)務(wù)開發(fā)的主流語言,再加上云原生技術(shù)底座的驅(qū)動(dòng),Go語言風(fēng)光無限,下面這篇文章主要給大家介紹了關(guān)于Go你不得不知道的一些實(shí)用小技巧,需要的朋友可以參考下
    2022-11-11
  • Go開發(fā)環(huán)境搭建詳細(xì)介紹

    Go開發(fā)環(huán)境搭建詳細(xì)介紹

    由于目前網(wǎng)上Go的開發(fā)環(huán)境搭建文章很多,有些比較老舊,都是基于 GOPATH的,給新入門的同學(xué)造成困擾。以下為2023 版 Go 開發(fā)環(huán)境搭建,可參照此教程搭建Go開發(fā)環(huán)境,有需要的朋友可以參考閱讀
    2023-04-04
  • golang中切片copy復(fù)制和等號(hào)復(fù)制的區(qū)別介紹

    golang中切片copy復(fù)制和等號(hào)復(fù)制的區(qū)別介紹

    這篇文章主要介紹了golang中切片copy復(fù)制和等號(hào)復(fù)制的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang 占位符和fmt常見輸出介紹

    golang 占位符和fmt常見輸出介紹

    這篇文章主要介紹了golang 占位符和fmt常見輸出介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言中defer語句的用法

    Go語言中defer語句的用法

    這篇文章介紹了Go語言中defer語句的用法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07

最新評(píng)論