LoginSignup
46
40

More than 5 years have passed since last update.

rack middlewareのテストをrspecで書いてみた

Last updated at Posted at 2014-09-09

背景

middlewareといっても、基本はinitializeとcallの2つのメソッドだけのclass。
rackを継承してるわけでもないので、適当なアプリをmiddlewareに食わせてテストを書こうかなぁ…
と悩んでいると、いい記事を見つけた。

Rack MiddlewareのGemに対するRspecの書き方

やってることは、

  • callされたら適当なレスポンス返すだけのシンプルなアプリをテスト用に定義しておく
  • rackアプリをこれに食わせてnewしておく
  • Rack::Test::Methodsをincludeする

すると、Railsのcontrollerのテストのように、リクエストを投げて、そのレスポンスを使ってテストを書くことができる。

spec

先日作成したrack middlewareのテストを書いてみる。
middlewareはrack middlewareをざっくり触ってみたを参照。

callされたら適当なレスポンス返すだけのシンプルなアプリをテスト用に定義しておく
spec/support/test_application_helper.rb
module TestApplicationHelper
  extend self

  class TestApplication
    def call(env)
      code   = 200
      body   = [ "test body" ]
      header = { "Content-Type"           => "text/html;charset=utf-8",
                 "Content-Length"         => "9",
                 "X-XSS-Protection"       => "1; mode=block",
                 "X-Content-Type-Options" => "nosniff",
                 "X-Frame-Options"        => "SAMEORIGIN" }
      [ code, header, body ]
    end
  end
end
rackアプリをこれに食わせてnewしておく & Rack::Test::Methodsをincludeする

参照した記事にもあるが、appでrack_middlewareが返るようになっていれば、
HTTPリクエストを使ったテストができるようになる。

my_rack_middleware_spec.rb
describe MyRackMiddleware do
  include TestApplicationHelper
  include Rack::Test::Methods

  let(:test_app) { TestApplicationHelper::TestApplication.new }
  let(:app)      { MyRackMiddleware.new(test_app) }

  describe "GET '/hoge'" do
    it 'should return 200 OK' do
      get '/hoge'

      expect(last_response.status).to eq 200
      expect(last_response.body).to eq html
      expect(last_response.header["Content-Type"]).to eq "text/html;charset=utf-8"
      expect(last_response.header["Content-Length"].to_i).to be > 0
      expect(last_response.header["X-XSS-Protection"]).to eq "1; mode=block"
      expect(last_response.header["X-Content-Type-Options"]).to eq "nosniff"
      expect(last_response.header["X-Frame-Options"]).to eq "SAMEORIGIN"
    end
  end
end

last_request & last_response

Rack::Test::Methodsでリクエストを送信すると、last_request、last_responseそれぞれに値が格納される。
上記のテストのようにこれを使ってテストを書く。

last_request

テスト中で最後に送信したリクエスト。

  • middlewareのcallで受け取るenvがそのままリクエストに入っている
  • middlewareでリクエストを上書いた場合や追加した場合はlast_requestに反映される
  • bodyはrack.inputに格納されている (別記事参照)
last_reqeuest
last_request.class      #=> Rack::Request
last_request.env.class  #=> Hash
last_request.env        #=> 
{ "rack.version"      => [1, 2],
  "rack.input"        => #<StringIO:0x00000002a17708>,
  "rack.errors"       => #<StringIO:0x00000002a17f00>,
  "rack.multithread"  => true,
  "rack.multiprocess" => true,
  "rack.run_once"     => false,
  "REQUEST_METHOD"    => "GET",
  "SERVER_NAME"       => "example.org",
  "SERVER_PORT"       => "80",
  "QUERY_STRING"      => "",
  "PATH_INFO"         => "/hoge",
  "rack.url_scheme"   => "http",
  "HTTPS"             => "off",
  "SCRIPT_NAME"       => "",
  "CONTENT_LENGTH"    => "0",
  "rack.test"         => true,
  "REMOTE_ADDR"       => "127.0.0.1",
  "HTTP_HOST"         => "example.org",
  "HTTP_COOKIE"       => "" }

last_response

テスト中で最後に受信したレスポンス

  • RackのMockReponseが返ってくる
  • status, body, headersへのaccessorが付いている
  • Content-Lengthはlengthでアクセスできる
last_response
last_response.class    #=> Rack::MockResponse
last_response.body     #=> "hogehoge"
last_response.errors   #=> ""
last_response.headers  #=>
{ "Content-Type"           => "text/html;charset=utf-8",
  "Content-Length"         => "8",
  "X-XSS-Protection"       => "1; mode=block",
  "X-Content-Type-Options" => "nosniff",
  "X-Frame-Options"        => "SAMEORIGIN" }
last_response.length   #=> 8
last_response.status   #=> 200

ちなみに、Rack::Test::Methodsでリクエストを送信前にlast_request、last_responseにアクセスするとエラーになる。

last_request   #=> Rack::Test::Error: No request yet. Request a page first.
last_response  #=> Rack::Test::Error: No response yet. Request a page first.

参考

46
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
40