2 回答

TA貢獻1847條經(jīng)驗 獲得超7個贊
如果目標是驗證查詢是否有效并實際針對流入執(zhí)行,則沒有針對流入實際執(zhí)行這些查詢的快捷方式。這些通常被認為是“集成”測試。我發(fā)現(xiàn)使用 docker-compose,這些測試可以與單元測試一樣可靠,并且足夠快,可以集成到 CI 中。在 CI 中執(zhí)行測試使本地工程師能夠輕松運行這些測試來驗證他們的查詢更改。
我想到處都有存儲庫,即使對于小型服務(wù),只是為了它們可測試,似乎是過度設(shè)計的。
我發(fā)現(xiàn)這是一個相當兩極分化的討論。測試實現(xiàn)是一種具體的實現(xiàn),為可靠、可重復(fù)的測試鋪平了道路,這些測試支持輕松隔離和執(zhí)行代碼的特定組件。
我想對此進行單元測試,但我不知道該怎么做,
我認為這是非常微妙的,IMO 單元測試查詢提供了負值。價值來自于使用存儲庫接口,允許您的單元測試顯式配置您將從 influx 收到的響應(yīng),以便充分運用您的應(yīng)用程序代碼。這不會提供有關(guān)流入的反饋,這就是為什么集成測試對于驗證您的應(yīng)用程序是否可以針對流入進行有效配置、連接和查詢至關(guān)重要。當您部署應(yīng)用程序時,這種驗證會隱式發(fā)生,此時就反饋而言,它比在本地和通過集成測試在 CI 中驗證它要昂貴得多。
我創(chuàng)建了一個圖表來嘗試說明這些差異:
使用存儲庫的單元測試側(cè)重于您的應(yīng)用程序代碼,并且對與流入有關(guān)的任何內(nèi)容提供很少的反饋/價值。集成測試對于驗證您的客戶端很有用(可能會擴展到您的應(yīng)用程序,具體取決于測試的執(zhí)行位置,但我更喜歡將其綁定到客戶端,因為您已經(jīng)獲得了來自接口和調(diào)用的靜態(tài)反饋)。最后,正如 @Markus 指出的那樣,從集成測試到 e2e 測試的步驟非常小,并且允許您測試完整的服務(wù)。

TA貢獻1831條經(jīng)驗 獲得超10個贊
根據(jù)其定義,如果您測試與外部資源的集成,我們談?wù)摰氖羌蓽y試,而不是單元測試。所以我們這里有兩個問題需要解決。
單元測試
您通常要做的就是擁有一個接受接口的數(shù)據(jù)訪問層,這反過來又很容易模擬,并且您可以對應(yīng)用程序邏輯進行單元測試。
package main
import (
"errors"
"fmt"
)
var (
values = map[string]string{"foo": "bar", "bar": "baz"}
Expected = errors.New("Expected error")
)
type Getter interface {
Get(name string) (string, error)
}
// ErrorGetter implements Getter and always returns an error to test the error handling code of the caller.
// ofc, you could (and prolly should) use some mocking here in order to be able to test various other cases
type ErrorGetter struct{}
func (e ErrorGetter) Get(name string) (string, error) {
return "", Expected
}
// MapGetter implements Getter and uses a map as its datasource.
// Here you can see that you actually get an advantage: you decouple your logic from the data source,
// making refactoring (and debugging) **much** easier WTSHTF.
type MapGetter struct {
data map[string]string
}
func (m MapGetter) Get(name string) (string, error) {
if v, ok := m.data[name]; ok {
return v, nil
}
return "", fmt.Errorf("No value found for %s", name)
}
type retriever struct {
g Getter
}
func (r retriever) retrieve(name string) (string, error) {
return r.g.Get(name)
}
func main() {
// Assume this is test code. No tests possible on playground ;)
bad := retriever{g: ErrorGetter{}}
s, err := bad.retrieve("baz")
if s != "" || err == nil {
panic("Something went seriously wrong")
}
// Needs to fail as well, as "baz" is not in values
good := retriever{g: MapGetter{values}}
s, err = good.retrieve("baz")
if s != "" || err == nil {
panic("Something went seriously wrong")
}
s, err = good.retrieve("foo")
if s != "bar" || err != nil {
panic("Something went seriously wrong")
}
}
在上面的示例中,我實際上必須實現(xiàn)兩個 Getter 來覆蓋所有測試用例,因為我無法使用模擬庫,但您明白了。
至于過度工程:簡單明了,不,這不是過度工程。這就是我個人所說的正確的工藝。從長遠來看,習慣它是值得的。也許不是在這個項目中,但在未來的一個項目中。
集成測試
狡猾的。我傾向于做的是在提交之前確保我的查詢是正確的;)
在極少數(shù)情況下,我確實想在 CI 中驗證我的查詢,例如,我通常創(chuàng)建一個 Makefile,它反過來啟動一個 docker(-compose),它提供我想要集成的內(nèi)容,然后運行測試。
- 2 回答
- 0 關(guān)注
- 143 瀏覽
添加回答
舉報