1. ホーム
  2. unit-testing

[解決済み] Goのモック関数

2022-04-22 13:34:02

質問

依存関係に戸惑っています。いくつかの関数呼び出しをモックに置き換えることができるようにしたいのです。以下は、私のコードのスニペットです。

func get_page(url string) string {
    get_dl_slot(url)
    defer free_dl_slot(url)
    
    resp, err := http.Get(url)
    if err != nil { return "" }
    defer resp.Body.Close()
    
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil { return "" }
    return string(contents)
}

func downloader() {
    dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
    content := get_page(BASE_URL)
    links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
    matches := links_regexp.FindAllStringSubmatch(content, -1)
    for _, match := range matches{
        go serie_dl(match[1], match[2])
    }
}

をテストできるようにしたいんです。 downloader() をモックすることで、実際に http でページを取得する必要はありません。 get_page (ページの内容だけを文字列として返すので簡単です) あるいは http.Get() .

見つけた このスレッド というのは、同じような問題についてのようです。Julian Phillips氏のライブラリーを紹介します。 ウィズモック を解決策としたのですが、うまくいきません。以下は私のテストコードの関連部分ですが、正直なところ、私にとっては大部分がカーゴカルトコードです。

import (
    "testing"
    "net/http" // mock
    "code.google.com/p/gomock"
)
...
func TestDownloader (t *testing.T) {
    ctrl := gomock.NewController()
    defer ctrl.Finish()
    http.MOCK().SetController(ctrl)
    http.EXPECT().Get(BASE_URL)
    downloader()
    // The rest to be written
}

テスト出力は以下の通りです。

<ブロッククオート

ERROR: Failed to install '_et/http': exit status 1 output: can't load パッケージ: パッケージ _et/http: http (chunked.go) と main パッケージが見つかりました。 (main_mock.go)の中にあります。

/var/folders/z9/ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http

Withmockは私のテストの問題を解決してくれるのでしょうか?動作させるためにはどうすればいいのでしょうか?

どのように解決するのですか?

個人的に、私は gomock (あるいはモッキングフレームワークも。Goのモッキングはこれなしでもとても簡単です)。私なら downloader() 関数をパラメータとして使用するか、あるいは downloader() を型に対するメソッドとし、その型に get_page 依存関係があります。

方法1:パス get_page() のパラメータとして downloader()

type PageGetter func(url string) string

func downloader(pageGetterFunc PageGetter) {
    // ...
    content := pageGetterFunc(BASE_URL)
    // ...
}

メインです。

func get_page(url string) string { /* ... */ }

func main() {
    downloader(get_page)
}

テストします。

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader(t *testing.T) {
    downloader(mock_get_page)
}

方法2:作る download() 型のメソッド Downloader :

もし、依存関係をパラメータとして渡したくないのであれば、このように get_page() をある型のメンバとし download() をその型のメソッドとして使用し、そのメソッドで get_page :

type PageGetter func(url string) string

type Downloader struct {
    get_page PageGetter
}

func NewDownloader(pg PageGetter) *Downloader {
    return &Downloader{get_page: pg}
}

func (d *Downloader) download() {
    //...
    content := d.get_page(BASE_URL)
    //...
}

メインです。

func get_page(url string) string { /* ... */ }

func main() {
    d := NewDownloader(get_page)
    d.download()
}

テストします。

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader() {
    d := NewDownloader(mock_get_page)
    d.download()
}