LoginSignup
3
2

More than 1 year has passed since last update.

request spec 以外でも `get` や `response` を使うには

Last updated at Posted at 2022-07-15

結論から言うと以下のように呼び出すことが出来ます。
バージョンは rspec (3.11.0) です。

RSpec.describe MyClass do
  let(:integration_test) { ActionDispatch::IntegrationTest.new(nil) }
  context do
    it do
      integration_test.get('/path/to')
      expect(integration_test.response.status).to be 200
    end
  end
end

Request spec 以外のクラスのテストでどうしても API を呼び出した結果のレスポンスが欲しい場合、どうやって呼び出すか調べてみました(そもそもそういうテストは書くべきでないという話は置いといて)。

Request spec 内で binding.pry して止めてみます。

RSpec.describe MyController, type: :request do
  it do
    binding.pry
  end
end

get がどこで定義されているか調べてみます。

> method(:get).source_location
=> ["/Users/kurashita/TestApp/vendor/bundle/ruby/3.0.0/gems/actionpack-6.1.6/lib/action_dispatch/testing/integration.rb", 369]

以下に定義されていることがわかりました。

TestApp/vendor/bundle/ruby/3.0.0/gems/actionpack-6.1.6/lib/action_dispatch/testing/integration.rb
%w(get post patch put head delete cookies assigns follow_redirect!).each do |method|
  # reset the html_document variable, except for cookies/assigns calls
  unless method == "cookies" || method == "assigns"
    reset_html_document = "@html_document = nil"
  end

  definition = RUBY_VERSION >= "2.7" ? "..." : "*args"

  module_eval <<~RUBY, __FILE__, __LINE__ + 1
    def #{method}(#{definition})
      #{reset_html_document}

      result = integration_session.#{method}(#{definition})
      copy_session_variables!
      result
    end
  RUBY
end

ActionDispatch::Integration::Runner モジュールに動的に定義されているようです。
このモジュールは ActionDispatch::IntegrationTest でインクルードされているのでこれをインスタンス化すれば使えそう、というところであとは継承してるクラスをたどって行くだけなので割愛します。

ちなみに以下のコードで、

actionpack-6.1.6/lib/action_dispatch/testing/integration.rb#L368
module_eval <<~RUBY, __FILE__, __LINE__ + 1
  def #{method}(#{definition})
    #{reset_html_document}

    result = integration_session.#{method}(#{definition})
    copy_session_variables!
    result
  end
RUBY

integration_session の同名のメソッドを呼んでおり、この中身は ActionDispatch::Integration::Session クラスのインスタンスなのでこれを呼ぶことでも使用可能です。

let(:session) { ActionDispatch::Integration::Session.new(Rails.application) }
it do
  session.get('/path/to')
end
3
2
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
3
2