WebMockとHTTPartyで request spec にハマった話
久しぶりの更新になります。 今年はいろいろアウトプットできるといいですね。。。
今回は仕事沼ったことを、軽く、雑に、ウォームアップ感覚で書いていきたいと思います。
実装したAPIに request specを書くためとき、処理の中で外部のAPIにリクエストを送ることがあるかと思います。 specの中で実際にリクエストを飛ばされると困るし、テストしずらいので webmock という便利なgemが用意されています。
webmockを使うことによってstubしたurlに対して、どんなレスポンスを返すか指定することができます
その上で今回はHTTPartyを使用してリクエストを送る想定で進めます。
例えばコントローラーにこんな処理があったとします(とても雑に)
def index response = HTTParty.get("https://somesampleapi.com/posts/1") render json: response, status: :ok end
これに対してこんな感じにstub_requestしたテストを書くことが可能です。
let(:exepcted_response) do { "userId": 1, "id": 1, "title": "hogehoge", "body": "fugafuga" } end it "外部からレスポンスを取得できること" do stub_request(:get, "https://somesampleapi.com/posts/1") .to_return(status: 200, body: exepcted_response.to_json) get posts_url expect(response).to have_http_status(:ok) expect(response.body).to eq exepcted_response.to_json end
しかし、resopnse.body がなぜか空のhashを返してました。
Failure/Error: expect(response.body).to eq exepcted_response.to_json expected: "{\"userId\":1,\"id\":1,\"title\":\"hogehoge\",\"body\":\"fugafuga\"}" got: "{}"
controllerをbinding.pryで覗くと以下のようになっていました
def index response = HTTParty.get("https://somesampleapi.com/posts/1") binding.pry render json: response, status: :ok end [10] pry(#<PostsController>)> response.class => HTTParty::Response [11] pry(#<PostsController>)> response.to_json => "{}" [12] pry(#<PostsController>)> response => "{\"userId\":1,\"id\":1,\"title\":\"hogehoge\",\"body\":\"fugafuga\"}"
renderにresopnseを渡すと、to_jsonが内部で自動で呼ばれた気がします(うろ覚え。。) なのでrender で to_jsonされた結果空のハッシュが返ってくるようです。
解決方法
結果、webmockの方に解決方法書いてありました
Set appropriate Content-Type for HTTParty's parsed_response.
stub_request(:any, "www.example.com").to_return body: '{}', headers: {content_type: 'application/json'}
ヘッダーコンテンツの中身しっかり書いておいてね〜という内容でした。 ということで、stub_requstを修正して、もう一度responseの中身を確認してみました。
stub_request(:get, "https://somesampleapi.com/posts/1") .to_return(status: 201, body: exepcted_response.to_json, headers: {content_type: "application/json"})
[1] pry(#<PostsController>)> response => {"userId"=>1, "id"=>1, "title"=>"hogehoge", "body"=>"fugafuga"} [2] pry(#<PostsController>)> response.class => HTTParty::Response [4] pry(#<PostsController>)> response.to_json => "{\"userId\":1,\"id\":1,\"title\":\"hogehoge\",\"body\":\"fugafuga\"}"
今回は to_json
で空が入ってこなかったですね。 なのでspec側も動くはず
Finished in 0.07161 seconds (files took 1.6 seconds to load) 1 example, 0 failures
🙌 🙌 🙌 🙌
WebMock側かHTTParty側の問題の切り分けは必要でしたが、結局ドキュメントを先に見ていればある程度早く解決できたかもしれないです。 Official Document を真っ先にみよう!
今回は調べきれてないですが、 HTTPartyの挙動も気になりますなぁ。。
久しぶりに書いてみて、用語の意味が曖昧だったり、説明しきれてない部分、自分の理解してない部分が書いていてどんどん出てきました。これ良い学習になるな!と思いつつも、ガチガチにやるとリタイアしそうなので、最初のうちは軽く、ゆるく、長くできるようなスタンスで進めたいな(願望