Rails 4 rspec 3控制器测试:会话助手模块不能用于之前(:all),适用于之前(:每个)

时间:2017-04-07 23:57:48

标签: ruby-on-rails rspec rspec-rails

我正在使用Rails 4.2.7构建一个玩具聊天应用程序,并且正在使用rspec 3.5为我的控制器编写规范。我的Api::ChatroomsController要求用户登录才能创建聊天室,因此我创建了一个Api::SessionsHelper模块,以便在Api::ChatroomsController规范中创建会话。

# app/helpers/api/sessions_helper.rb
module Api::SessionsHelper
  def current_user
    User.find_by_session_token(session[:session_token])
  end

  def create_session(user)
    session[:session_token] = user.reset_session_token!
  end

  def destroy_session(user)
    current_user.try(:reset_session_token!)
    session[:session_token] = nil
  end
end


# spec/controllers/api/chatrooms_controller_spec.rb
require 'rails_helper'
include Api::SessionsHelper

RSpec.describe Api::ChatroomsController, type: :controller do
  before(:all) do
    DatabaseCleaner.clean
    User.create!({username: "test_user", password: "asdfasdf"})
  end

  user = User.find_by_username("test_user")

  context "with valid params" do
    done = false

    # doesn't work if using a before(:all) hook
    before(:each) do
      until done do
        create_session(user)
        post :create, chatroom: { name: "chatroom 1" }
        done = true
      end
    end

    let(:chatroom) { Chatroom.find_by({name: "chatroom 1"}) }
    let(:chatroom_member) { ChatroomMember.find_by({user_id: user.id, chatroom_id: chatroom.id}) }

    it "responds with a successful status code" do
      expect(response).to have_http_status(200)
    end

    it "creates a chatroom in the database" do
      expect(chatroom).not_to eq(nil)
    end

    it "adds the chatroom creator to the ChatroomMember table" do
      expect(chatroom_member).not_to eq(nil)
    end
  end

end

我正在使用带有布尔变量before(:each)的{​​{1}}挂钩来实现done挂钩的行为,以创建单个会话。

如果我使用before(:all)钩子,我会收到错误:

before(:all)

我在Api :: SessionsHelper模块的create_session方法中放置一个调试器来检查NoMethodError: undefined method `session' for nil:NilClass` ,在这两种情况下,当我使用self.class时,当我使用before(:each)时,该类是:

before(:all)

但是,当使用RSpec::ExampleGroups::ApiChatroomsController::WithValidParams 挂钩时,会话为before(:each),而在{}挂钩中,会话会提供上面的before(:all)

有人知道造成这个错误的原因吗?

1 个答案:

答案 0 :(得分:0)

您需要在测试块中包含帮助程序:

RSpec.describe Api::ChatroomsController, type: :controller do
  include Api::SessionsHelper
end

您还可以通过在spec/rails_helper.rb

中加入常见的规范帮助程序来避免重复
RSpec.configure do |config|
  # ...
  config.include Api::SessionsHelper, type: :controller
end

这也是你应该放置database_cleaner配置的地方。您应该在每个规范之间进行清理,而不是之前,因为这将导致测试订购问题和扑动测试。

require 'capybara/rspec'

#...

RSpec.configure do |config|

  config.include Api::SessionsHelper, type: :controller
  config.use_transactional_fixtures = false

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
        (or set it to false) to prevent uncommitted transactions being used in
        JavaScript-dependent specs.

        During testing, the app-under-test that the browser driver connects to
        uses a different database connection to the database connection used by
        the spec. The app's database connection would not be able to access
        uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so continue to use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      # Driver is probably for an external browser with an app
      # under test that does *not* share a database connection with the
      # specs, so use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.append_after(:each) do
    DatabaseCleaner.clean
  end

end