gockでHTTPリクエストをMockする
はじめに
最近はGo言語でWebアプリを書く際に使う諸々のライブラリを試してみているのですが、今はMockサーバをいろいろ見ていました。
Goの場合は標準ライブラリでもhttptestでいろいろ用意されていているみたいです。ただちょっと、そのまま使うには手間が多そうに感じ、ほかを探してるとgockというのが良さげだったのでちょっと試してみようと思います。
gockとは
Go製のHTTPのMockライブラリーです。
以下のような特徴があります。
gockはhttp.Client
で利用されるhttp.DefaultTransport
かもしくはカスタムhttp.Transport
を経由して、HTTPのアウトバウンドのリクエストをモックします。
登録されたMockがFIFOでリクエストにマッチするかの検証が行われ、マッチした場合MockのHTTPレスポンスを返します。
そして、どのMockにもマッチしなかった場合は基本的にはエラーが起こるようです。ただし、リアルネットワークモードが有効化されている場合は実際のリクエストが代わりに実行されます。
このブログではあまり複雑なことはせずにひとまず動かしてみるところまでやってみようかと思います。
使ってみる
環境
プログラムを動かす環境は以下の通り
$ go version go version go1.16 linux/amd64 $ uname -srvmpio Linux 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a LSB Version: core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch Distributor ID: Ubuntu Description: Ubuntu 20.04.2 LTS Release: 20.04 Codename: focal
プロジェクトを作る
プロジェクトを作成して、TestifyとGockをインストトールします。
$ go get github.com/stretchr/testify go get: added github.com/stretchr/testify v1.7.0 $ go get -u gopkg.in/h2non/gock.v1 go get: added gopkg.in/h2non/gock.v1 v1.0.16
これで下準備までは環境です。
Pongの文字列を返すMockを作る
準備ができたので、早速使っていこうと思います。
localhost:8081/ping
に対して”pong”
の文字列のレスポンス返す場合は以下のようにします。
import ( "github.com/stretchr/testify/assert" "gopkg.in/h2non/gock.v1" "io" "log" "net/http" "testing" ) const ( MOCK_URL = "localhost:8082" PING_PATH = "/ping" ) func TestName(t *testing.T) { defer gock.Off() gock.New(MOCK_URL). Get(PING_PATH). Reply(200). BodyString("pong") res, err := http.Get("http://" + MOCK_URL + PING_PATH) handleError(err) bodyByte, err := io.ReadAll(res.Body) handleError(err) assert.Equal(t, 200, res.StatusCode) assert.Equal(t, "pong", string(bodyByte)) assert.Equal(t, gock.IsDone(), true) } func handleError(err error) { if err != nil { log.Fatal(err) } }
gock
でMockをたてる場合はgock.New(MOCK_URL)
のように宣言的にMockを定義することができます。また、リクエストのヘッダーやボディ、リクエストパラムでマッピングを作成したい場合はReply(200).
より前のリクエストのパターンを構成するビルダーのメソットチェインの中で、それぞれMatchHeader
、MatchBody
、JSON
(Jsonのリクエストボディを受け取る場合)、MatchHeader
などの関数を呼び出すことで行えます。
例えば、MatchHeader("x-api-version", "1.[0-9]")
のように記述することができ、この記述の場合、ヘッダーにキーがx-api-version
で値が1.(0から9までの数字)
を含むリクエストに対してマッチングします。
レスポンスを作成する場合はReply()
関数を呼び出し、レスポンスボディは今回は文字列を返すのでBodyString
を呼び出しています。JSONの値を返したい場合はJSONメソッドを呼び出して、JSON(map[string]string{"foo": "bar"})
のように記述します。
アサーション部分では、最後のところがポイントでgock.IsDone()
を呼び出すことですべての設定したモックが呼び出されているかの検証を行なうことができます。