2017-06-14 49 views
0

我有兩個結構:FunctionalityClientTestClient,都執行Interface。我有一個類型Interface的全局變量Client。我將Client分配給實際客戶端或模擬客戶端,具體取決於它是測試還是正常運行。如何在Golang中使用成員函數正確地模擬結構?

Interface有一個方法Request,我想模擬測試。也就是說,我想:

  • 記錄什麼是傳遞給函數的
  • 返回參數從功能

一些任意定義的返回值,因此結構是這樣的:

type TestClient struct { 
    recordedArgs []interface{} 
    returnValues []interface{} 
} 
func (c *TestClient) Request(body io.Reader, method string, endpoint string, headers []Header) ([]byte, error) { 
    c.recordedArgs = append(c.recordedArgs, []interface{}{body, method, endpoint, headers}) // this can't be typed if I want the code to be reusable 
     if len(c.returnValues) != 0 { 
     last := c.returnValues[0] 
     c.returnValues = c.returnValues[1:] 
     return last.([]byte), nil 
    } 
    return nil, nil 
} 

我用它像這樣:

testClient := TestClient{ 
    returnValues: []interface{}{ 
     []byte("arbitrarily defined return value"), 
     []byte("this will be returned after calling Request a second time"), 
    } 
} 
Client = &testClient 
// run the test 
// now let's check the results 
r1 := testClient.recordedArgs[1].([]interface{}) // because I append untyped lists to recordedArgs 
assert.Equal(t, "POST", r1[1].(string)) 
assert.Equal(t, "/file", r1[2].(string)) 
// and so on 

現在的問題。

我有幾個結構,我想嘲笑這樣的。目前我只是複製並粘貼上面的代碼爲每個結構。但這真的很糟糕,我希望模擬邏輯能夠以某種方式被抽象出來。我也會接受像Mockito的when這樣的東西:當使用特定參數調用模擬函數時,返回一個特定值並記錄調用。

我怎樣才能正確地模擬一個結構與Golang中的成員函數?

+0

因爲您知道每個元素都將是[] interface {},所以您可以通過設置recordedArgs a [] [] interface {}來簡化這一點。它爲您節省了一些不必要的類型斷言。 – Adrian

回答

0

如果您正在模擬客戶端使用HTTP API,您可能只需要使用httptest.Server,這可以極大地簡化這個過程。而不是嘲笑客戶端,嘲笑客戶端連接的服務器。它非常易於使用,並且您仍然可以記錄請求方法,路徑,主體等,以及以與模擬客戶端相同的方式返回任意響應值。

如果這不是一個選項,你可以抽象出你的模擬方法,以使其可重複使用:

type TestClient struct { 
    recordedArgs [][]interface{} 
    returnValues []interface{} 
} 

func (c *TestClient) mock(args ...interface{}) interface{} { 
    c.recordedArgs = append(c.recordedArgs, args) 
    if len(c.returnValues) != 0 { 
     last := c.returnValues[0] 
     c.returnValues = c.returnValues[1:] 
     return last 
    } 
    return nil 
} 

func (c *TestClient) Request(body io.Reader, method string, endpoint string, headers []Header) ([]byte, error) { 
    return c.mock(body,method,endpoint,headers).([]byte), nil 
} 

這樣可以減少您的具體使用情況的方法下到一線。

相關問題