为了账号安全,请及时绑定邮箱和手机立即绑定

我可以为我的测试用例编写我自己版本的 go 的 http client.Do() 函数吗?

我可以为我的测试用例编写我自己版本的 go 的 http client.Do() 函数吗?

Go
九州编程 2022-11-23 20:25:10

我有一个名为 user-service.go 的文件和相应的测试文件,名为 user-service_test.go。当我试图获得完整的代码覆盖率时,我正在努力让一些错误条件真正发生。


这是函数:GetOrCreateByAccessToken()


//GetOrCreateByAccessToken gets a user from the database with the given access token

func (s *service) GetOrCreateByAccessToken(aT string, client *Client) (*user.User, fcerr.FCErr) {


var currentUser user.OauthUser


req, err := http.NewRequest("GET", "https://openidconnect.googleapis.com/v1/userinfo?access_token="+aT, nil)

if err != nil {

    return nil, fcerr.NewInternalServerError("Error when setting up the network request")

}


response, err := client.httpClient.Do(req)

if err != nil {

    fmt.Println("error when getting the userinfo with the access token")

    return nil, fcerr.NewInternalServerError("Error when trying to verify user identity")

}


defer response.Body.Close()


contents, err := io.ReadAll(response.Body)

if err != nil {

    return nil, fcerr.NewInternalServerError("Error when trying to read response from Google about user identity")

}

我对测试的主要控制是我可以传入 *Client。


这是测试用例的一部分,我想让 io.ReadAll 抛出一个错误:


h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

    //manually return the message google would return on an actual request

    w.Write([]byte(googleAPIOKResponse))

})

//Call the testHTTPClient() function defined in the test file to substitute my own HandlerFunc

httpClient, teardown := testHTTPClient(h)

defer teardown()


//Call the real NewClient() from my user-service.go

client := NewClient()


//Substitute the default httpClient for the one I've just set up.

client.httpClient = httpClient


resultingUser, err := userService.GetOrCreateByAccessToken(nU.AccessToken, client)


assert.Nil(t, resultingUser)

assert.NotNil(t, err)

assert.Equal(t, http.StatusInternalServerError, err.Status())

有什么地方我可以编写自己的 .Do() 方法版本,该方法会在响应中放置一些内容,这会导致 io.ReadAll 返回错误?或者是否有更好的方法来仅使用我已经使用的预烘焙响应文本来实现错误?


查看完整描述

1 回答

?
萧十郎

TA贡献1527条经验 获得超11个赞

没有一种方法可以替代 Do 方法,但是有一种方法可以实现您的目标。


创建一个返回任意响应主体的往返类型:


type respondWithReader struct{ body io.Reader }


func (rr respondWithReader) RoundTrip(req *http.Request) (*http.Response, error) {

    return &http.Response{

        Proto:      "HTTP/1.0",

        ProtoMajor: 1,

        Header:     make(http.Header),

        Close:      true,

        Body:       ioutil.NopCloser(rr.body),

    }, nil


}

创建一个失败的 io.Reader:


var errReadFail = errors.New("blah!")


type failReader int


func (failReader) Read([]byte) (int, error) {

    return 0, errReadFail

}

将 stock 客户端与上面的传输和阅读器一起使用:


c := http.Client{Transport: respondWithReader{body: failReader(0)}}

resp, err := c.Get("http://whatever.com")

if err != nil {

    t.Error(err)

}

defer resp.Body.Close()


// ReadAll returns errReadFail

_, err = ioutil.ReadAll(resp.Body)

if err != errReadFail {

    t.Errorf("got err %v, expect %v", err, errReadFail)

}


查看完整回答
反对 回复 2022-11-23

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信