JavaScript를 실행하는 기능 사양에서 ActiveRecord에 원숭이 패치를 제거하는 방법

10550 단어 CapybaraRSpecRails

Rails의 기능 사양에서 자주 발생하는 문제



Rails의 피쳐 스펙으로 js: true 로 한다(테스트 실행시에 JavaScript도 움직이는) 경우, 피쳐 스펙내에서 작성한 테스트 데이터가 브라우저(Poltergeist나 Selenium webdriver로 기동하는 Firefox)내에서 참조할 수 없다고 하는 문제가 자주 발생 한다.

다음은 문제가 발생하는 기능 사양의 예입니다.
require 'rails_helper'

feature 'User management' do
  scenario "adds a new user", js: true do
    admin = create(:admin)

    visit root_path
    click_link 'Log In'
    fill_in 'Email', with: admin.email
    fill_in 'Password', with: admin.password
    # 上で作成したadminのデータがブラウザ側で参照できないのでログインに失敗する
    click_button 'Log In'

    # ...
  end
end

이 문제는 테스트를 실행하는 코드의 DB 연결과 기능 사양 용 웹 서버가 사용하는 DB 연결이 별도이기 때문에 한 DB 트랜잭션 내에서 생성 된 데이터는 다른 DB 연결에서 볼 수 없습니다. 에 기인한다.

기존의 기존 솔루션(원숭이 패치 포함)



이 문제를 해결하기 위해 특수 원숭이 패치와 DatabaseCleaner를 사용하여 다음과 같은 해결책이 잘 취해졌습니다.

spec/support/shared_db_connection.rb
class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

spec/rails_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

RSpec.configure do |config|
  # ...

  config.use_transactional_fixtures = true

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with :truncation
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end

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

이것은 무엇을 하고 있는가 하면, 테스트 실행 코드와 피쳐 스펙용의 Web 서버로 DB 커넥션을 공유해, 어느 쪽에서라도 같은 데이터의 읽고 쓰기를 할 수 있도록 하고 있다.

최근 솔루션(원숭이 패치 없음)



그러나 ActiveRecord에 원숭이 패치를 맞춘다는 것은 검은 마술적이며 그다지 기분이 좋은 것은 아니다.

그래서 최신 DatabaseCleaner의 README에서는 위의 원숭이 패치를 사용하지 않고이 문제를 해결하는 방법이 실려있다.


spec/support/shared_db_connection.rb
# 不要になるのでファイルごと削除

spec/rails_helper.rb
RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        設定がおかしいので警告メッセージを表示 (省略)
      MSG
    end
    DatabaseCleaner.clean_with(:truncation)
  end  

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

  config.before(:each, type: :feature) do
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      DatabaseCleaner.strategy = :truncation
    end
  end

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

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

위의 설정은 간단히 말하면 다음과 같습니다.
  • js: true의 경우 ( driver_shares_db_connection_with_specsfalse의 경우)는 트랜잭션을 사용하지 않고 데이터를 읽고 씁니다. 트랜잭션을 사용하지 않으므로 어느 DB 연결에서도 같은 데이터를 참조할 수 있다. 테스트가 끝나면 모든 데이터를 truncate합니다.
  • 그렇지 않으면 DB 연결이 하나뿐이므로 트랜잭션 내에서 데이터를 읽고 씁니다.

  • 동작 확인한 실행 환경



    필자는 이하의 환경에서 「원숭이 패치를 사용하지 않는 해결책」이 유효하게 기능하는 것을 확인했다.

    이전 버전의 gem에서는 확인하지 않았기 때문에, 이 해결책을 적용하는 경우는 테스트 관련의 gem은 가능한 한 최신으로 하는 것이 바람직하다.
  • Rails 5.0.0
  • rspec-rails 3.5.0
  • capybara 2.7.1
  • database_cleaner 1.5.3
  • selenium-webdriver 2.53.4
  • factory_girl_rails 4.7.0

  • 샘플 코드



    Everyday Rails - RSpec에 의한 Rails 테스트 입문 샘플 응용 프로그램을 기반으로 위의 솔루션을 적용했습니다.

    테스트 코드의 내용은 아래의 GitHub 리포지토리에서 확인할 수 있다.

    이 설정이 해결될 수 있는 문제



    Rails 5로 업데이트하면 요청 사양에서 다음과 같은 오류가 발생하여 테스트가 떨어질 수 있습니다.
    PG::ConnectionBad: PQsocket() can't get socket descriptor: ROLLBACK TO SAVEPOINT active_record_1
    

    테스트 관련 gem을 최신으로 하고 원숭이 패치를 사용하지 않는 해결책을 적용한 결과 이 ​​문제가 해결되었다.

    기타 : Everyday Rails의 독자 여러분에게



    Everyday Rails - RSpec에 의한 Rails 테스트 입문 에서는 「종래의 낡은 해결책」이 실려 있으므로, 적절히 「원숭이 패치를 사용하지 않는 해결책」을 사용해 주세요.

    구체적인 일정은 미정이지만 Everyday Rails도 Rails 5에 대응할 예정이므로, 그 때에는 최신의 해결책이 실려 있을 것입니다. .

    함께 읽고 싶다.



    Everyday Rails 샘플 애플리케이션을 Rails 5.0으로 업그레이드하는 방법을 설명하는 기사입니다.
    이쪽도 함께 부디.

    이것으로 더 이상 무섭지 않아! ? Rails 4.1에서 Rails 5.0으로 업그레이드하는 단계를 동영상으로 설명합니다.

    좋은 웹페이지 즐겨찾기