2015-02-11 61 views
2

我在Go中構建了一個快速且簡單的API,用於查詢ElasticSearch。現在我知道它可以完成,我想通過添加測試正確地做到這一點。我已經抽象了一些代碼,以便它可以進行單元測試,但是我一直在嘲笑彈性庫,因此我認爲如果我嘗試一個簡單的例子來嘲笑它,那將是最好的。Golang使用彈性模擬

import (
    "encoding/json" 
    "github.com/olivere/elastic" 
    "net/http" 
) 
... 
func CheckBucketExists(name string, client *elastic.Client) bool { 
    exists, err := client.IndexExists(name).Do() 
    if err != nil { 
     panic(err) 
    } 
    return exists 
} 

而且現在的測試...

import (
     "fmt" 
     "github.com/stretchr/testify/assert" 
     "github.com/stretchr/testify/mock" 
     "testing" 
) 

type MockClient struct { 
     mock.Mock 
    } 

    func (m *MockClient) IndexExists(name string) (bool, error) { 
     args := m.Mock.Called() 
     fmt.Println("This is a thing") 
     return args.Bool(0), args.Error(1) 
    } 

    func TestMockBucketExists(t *testing.T) { 
     m := MockClient{} 
     m.On("IndexExists", "thisuri").Return(true) 

>> r := CheckBucketExists("thisuri", m) 
     assert := assert.New(t) 
     assert.True(r, true) 
    } 

爲了這,我產生了具有以下錯誤:​​。

我假設這是我使用elastic.client類型的基本原理,但我仍然是一個noob過多。

回答

1

func CheckBucketExists(name string, client *elastic.Client) bool { 

指出CheckBucketExists期望一個*elastic.Client

線條:

m := MockClient{} 
m.On("IndexExists", "thisuri").Return(true) 
r := CheckBucketExists("thisuri", m) 

傳遞MockClientCheckBucketExists功能。

這是導致類型衝突。

也許你需要導入github.com/olivere/elastic到您的測試文件,然後執行:中

m := &elastic.Client{} 

代替

m := MockClient{} 

但我不是100%肯定你正在試圖做什麼。

0

這是一個老問題,但無法找到解決方案。 不幸的是,這個庫是用一個結構來實現,這使得嘲笑它不平凡的好,所以我覺得有三種選擇:

(1)包裹在接口上的所有elastic.SearchResult方法對你自己和「代理」的通話,所以你最終得到類似的東西:

type ObjectsearchESClient interface { 
    // ... all methods... 
    Do(context.Context) (*elastic.SearchResult, error) 
} 


// NewObjectsearchESClient returns a new implementation of ObjectsearchESClient 
func NewObjectsearchESClient(cluster *config.ESCluster) (ObjectsearchESClient, error) { 
    esClient, err := newESClient(cluster) 
    if err != nil { 
     return nil, err 
    } 

    newClient := objectsearchESClient{ 
     Client: esClient, 
    } 
    return &newClient, nil 
} 
// ... all methods... 
func (oc *objectsearchESClient) Do(ctx context.Context) (*elastic.SearchResult, error) { 
    return oc.searchService.Do(ctx) 
} 

然後嘲笑這個接口和響應,就像你會與你的應用程序的其他模塊一樣。

(2)另一種選擇是像指出在this blog post是模擬從其餘部分的響應調用使用httptest.Server

對於這一點,我嘲笑處理程序,即由嘲笑從「HTTP調用」響應的

func mockHandler() http.HandlerFunc{ 
    return func(w http.ResponseWriter, r *http.Request) { 
     resp := `{ 
      "took": 73, 
      "timed_out": false, 
      ... json ... 
      "hits": [... ] 
      ...json ... , 
      "aggregations": { ... } 
     }` 

     w.Write([]byte(resp)) 
    } 
} 

然後創建一個虛擬elastic.Client結構

func mockClient(url string) (*elastic.Client, error) { 
    client, err := elastic.NewSimpleClient(elastic.SetURL(url)) 
    if err != nil { 
     return nil, err 
    } 
    return client, nil 
} 

在這種情況下,我有一個庫,建立我的彈性。SearchService並返回,所以我使用HTTP這樣的:

... 
    ts := httptest.NewServer(mockHandler()) 
    defer ts.Close() 
    esClient, err := mockClient(ts.URL) 
    ss := elastic.NewSearchService(esClient) 
    mockLibESClient := es_mock.NewMockSearcherClient(mockCtrl) 
    mockLibESClient.EXPECT().GetEmployeeSearchServices(ctx).Return(ss, nil) 

其中mockLibESClient是我所提到的庫,我們存根mockLibESClient.GetEmployeeSearchServices方法使其返回與該SearchService將返回預期的有效載荷。

注:用於創建模擬mockLibESClient我用https://github.com/golang/mock

我發現這是令人費解,但「包裝」 elastic.Client是我的觀點更多的工作。

問題:我試圖通過使用https://github.com/vburenin/ifacemaker來創建一個接口,然後用https://github.com/golang/mock和類似的方法來模擬它的接口,但是當我試圖返回接口而不是結構時,我不是一個期望的人,所以我可能需要更好地理解類型轉換才能解決這個問題。所以如果你們中的任何一個知道如何做到這一點,請讓我知道。

+0

這是我最初的問題,自從我多年前發佈以來,我沒有做太多的工作。 [CodeReviewComments#Interfaces](https://github.com/golang/go/wiki/CodeReviewComments#interfaces)表明外部庫應該實現該結構,並且用戶應該在該結構上定義一個接口,並使用dep注射。其中,指出你在帖子中提到的第一個解決方案! – user2402831 2018-01-21 23:10:05