Goでhttpリクエスト
いくつか方法はあるようだが、
client := &http.Client{
CheckRedirect: redirectPolicyFunc,
}
resp, err := client.Get("http://example.com")
req, err := http.NewRequest("GET", "http://example.com", nil)
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
こっちの書き方でクライアントを実装する(http.Client
を使用する)
実装コード
github.com
httpmock
を使わない例
- 以下のように実装できる(説明のためにちょっと修正)
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
func NewContentUsecase(c HttpClient) *ContentUsecase {
return &ContentUsecase{
httpClient: c,
}
}
type ContentUsecase struct {
httpClient HttpClient
}
func (content ContentUsecase) GetContent() (string, error) {
request, _ := http.NewRequest("GET", "https://google.com", nil)
resp, _ := content.httpClient.Do(request)
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
return string(byteArray), nil
}
- キモとなるのは
GetContent
の引数に渡されてくるContentUsecase
- この
ContentUsecase
がHttpClient
インターフェースを満たしており、それを引数で注入する
- テスト時にはこの引数に渡すものをmockすれば良い
テスト(httpmock
を使わない例)
type clientMock struct {
HttpClient
MockedDo func(req *http.Request) (*http.Response, error)
}
func (c *clientMock) Do(req *http.Request) (*http.Response, error) {
return c.MockedDo(req)
}
func TestGetContent(t *testing.T) {
t.Run("GetContent正常系", func(t *testing.T) {
spyMocked := &clientMock{
MockedDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewBufferString("OK")),
}, nil
},
}
contentUsecase := NewContentUsecase(spyMocked)
content, err := contentUsecase.GetContent()
if err != nil {
t.Errorf("err should be nil: %v", err)
}
if content != "OK" {
t.Errorf("Returned Content invalid: %v", content)
}
})
}
HttpClient
インターフェースの中身をMockする(Do
関数を置き換える)
- 実際のテストコードの中で
Do
関数が何を返すのかを実装してやれば良い(MockedDo
を実装する)
httpmock
を使う例
func GetContentUseMock() (string, error) {
request, _ := http.NewRequest("GET", "https://example.com", nil)
client := &http.Client{}
resp, _ := client.Do(request)
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
return string(byteArray), nil
}
テスト
func TestGetContentUseMock(t *testing.T) {
t.Run("GetContentUseMock正常系", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://example.com",
func(req *http.Request) (*http.Response, error) {
res := httpmock.NewStringResponse(200, "ok")
return res, nil
},
)
content, err := GetContentUseMock()
if err != nil {
t.Errorf("error should be nil: %v", err)
}
if content != "ok" {
t.Errorf("content invalid: %v", content)
}
})
}
RegisterResponder
に何を返すのかを書くだけ。