第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在測試中模擬嵌套客戶端

如何在測試中模擬嵌套客戶端

Go
慕容3067478 2022-06-01 11:38:26
我正在構(gòu)建一個簡單的函數(shù),該函數(shù)調(diào)用一個使用 GraphQL ( https://github.com/machinebox/graphql ) 返回 Post 的 API。我將邏輯包裝在如下所示的服務(wù)中:type Client struct {    gcl graphqlClient}type graphqlClient interface {    Run(ctx context.Context, req *graphql.Request, resp interface{}) error}func (c *Client) GetPost(id string) (*Post, error) {    req := graphql.NewRequest(`        query($id: String!) {          getPost(id: $id) {            id            title          }        }    `)    req.Var("id", id)    var resp getPostResponse    if err := c.gcl.Run(ctx, req, &resp); err != nil {        return nil, err    }    return resp.Post, nil}現(xiàn)在我想為函數(shù)添加測試表GetPost,當設(shè)置為空字符串時會出現(xiàn)失敗情況,id這會導致下游調(diào)用出錯c.gcl.Run。我正在努力解決的是gcl客戶端可以被模擬并強制返回錯誤的方式(當沒有真正的 API 調(diào)用發(fā)生時)。我不確定是否response像這樣傳遞給模擬是正確的方法。此外,我正在努力為響應(yīng)設(shè)置正確的值,因為interface{}傳遞了一個類型,但我不知道如何將其轉(zhuǎn)換為getPostResponse并將值設(shè)置為Post那里。
查看完整描述

1 回答

?
郎朗坤

TA貢獻1921條經(jīng)驗 獲得超9個贊

您的測試用例不應(yīng)超出實現(xiàn)范圍。我特別指的是空對非空輸入或任何類型的輸入。


讓我們看一下您要測試的代碼:


func (c *Client) GetPost(id string) (*Post, error) {

    req := graphql.NewRequest(`

        query($id: String!) {

            getPost(id: $id) {

                id

                title

            }

        }

    `)

    req.Var("id", id)


    var resp getPostResponse

    if err := c.gcl.Run(ctx, req, &resp); err != nil {

        return nil, err

    }

    return resp.Post, nil

}

上面的實現(xiàn)中沒有任何東西基于id參數(shù)值做任何事情,因此在你的這段代碼的測試中沒有任何東西應(yīng)該真正關(guān)心傳入的輸入,如果它與實現(xiàn)無關(guān),它也應(yīng)該與測試無關(guān)。


您GetPost基本上有兩個基于單個因素的代碼分支,即返回err變量的“零”。這意味著就您的實現(xiàn)而言,根據(jù)返回的err值,只有兩種可能的結(jié)果,Run因此應(yīng)該只有兩個測試用例,第三個或第四個測試用例只是一個變體,如果不是一個完整的副本, 前兩個。


你的測試客戶端也在做一些不必要的事情,主要的是它的名字,即你所擁有的不是一個模擬,所以調(diào)用它是沒有幫助的。模擬通常不僅僅是返回預(yù)定義的值,它們確保方法被調(diào)用,以預(yù)期的順序和預(yù)期的參數(shù)等。實際上你根本不需要模擬,所以這是一件好事'語氣。


考慮到這一點,我建議您對測試客戶端執(zhí)行以下操作。


type testGraphqlClient struct {

    resp interface{} // non-pointer value of the desired response, or nil

    err  error       // the error to be returned by Run, or nil

}


func (g testGraphqlClient) Run(_ context.Context, _ *graphql.Request, resp interface{}) error {

    if g.err != nil {

        return g.err

    }


    if g.resp != nil {

        // use reflection to set the passed in response value

        // (i haven't tested this so there may be a bug or two)

        reflect.ValueOf(resp).Elem().Set(reflect.ValueOf(g.resp))

    }

    return nil

}

...這是必要的測試用例,所有兩個:


func TestClient_GetPost(t *testing.T) {

    tests := []struct {

        name   string

        post   *Post

        err    error

        client testGraphqlClient

    }{{

        name:   "return error from client",

        err:    errors.New("bad input"),

        client: testGraphqlClient{err: errors.New("bad input")},

    }, {

        name:   "return post from client",

        post:   &Post{id: aws.String("123")},

        client: testGraphqlClient{resp: getPostResponse{Post: &Post{id: aws.String("123")}}},

    }}


    for _, tt := range tests {

        t.Run(tt.name, func(t *testing.T) {

            client := Client{gql: tt.client}

            post, err := client.GetPost("whatever")

            if !cmp.Equal(err, tt.err) {

                t.Errorf("got error=%v want error=%v", err, tt.err)

            }

            if !cmp.Equal(post, tt.post) {

                t.Errorf("got post=%v want post=%v", post, tt.post)

            }

        })

    }

}

...這里有一些重復(fù),需要拼出postanderr兩次,但與更復(fù)雜/復(fù)雜的測試設(shè)置相比,這是一個很小的代價,它將從測試用例的預(yù)期輸出字段填充測試客戶端.


附錄:


如果您要GetPost以這樣一種方式進行更新,即在向 graphql 發(fā)送請求之前檢查空 id 并返回錯誤,那么您的初始設(shè)置將更有意義:


func (c *Client) GetPost(id string) (*Post, error) {

    if id == "" {

        return nil, errors.New("empty id")

    }

    req := graphql.NewRequest(`

        query($id: String!) {

            getPost(id: $id) {

                id

                title

            }

        }

    `)

    req.Var("id", id)


    var resp getPostResponse

    if err := c.gcl.Run(ctx, req, &resp); err != nil {

        return nil, err

    }

    return resp.Post, nil

}

...并相應(yīng)地更新測試用例:


func TestClient_GetPost(t *testing.T) {

    tests := []struct {

        name   string

        id     string

        post   *Post

        err    error

        client testGraphqlClient

    }{{

        name:   "return empty id error",

        id:     "",

        err:    errors.New("empty id"),

        client: testGraphqlClient{},

    }, {

        name:   "return error from client",

        id:     "nonemptyid",

        err:    errors.New("bad input"),

        client: testGraphqlClient{err: errors.New("bad input")},

    }, {

        name:   "return post from client",

        id:     "nonemptyid",

        post:   &Post{id: aws.String("123")},

        client: testGraphqlClient{resp: getPostResponse{Post: &Post{id: aws.String("123")}}},

    }}


    for _, tt := range tests {

        t.Run(tt.name, func(t *testing.T) {

            client := Client{gql: tt.client}

            post, err := client.GetPost(tt.id)

            if !cmp.Equal(err, tt.err) {

                t.Errorf("got error=%v want error=%v", err, tt.err)

            }

            if !cmp.Equal(post, tt.post) {

                t.Errorf("got post=%v want post=%v", post, tt.post)

            }

        })

    }

}


查看完整回答
反對 回復(fù) 2022-06-01
  • 1 回答
  • 0 關(guān)注
  • 105 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號