簡體   English   中英

Rails 4:使用 RSpec 測試 rake 任務時的 PG::InFailedSqlTransaction

[英]Rails 4: PG::InFailedSqlTransaction when testing a rake task with RSpec

我目前正在嘗試使用 RSpec 測試 rake 任務。 我的 Rails 版本是 4.2.4,rspec-rails 版本是 3.3.2。

我在rails_helper.rb 中有以下內容

ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara/rspec'

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

RSpec.configure do |config|
  ...

  config.use_transactional_fixtures = false
  config.infer_spec_type_from_file_location!
  ...
end

然后是spec/support/tasks.rb

require 'rake'

module TaskExampleGroup
  extend ActiveSupport::Concern

  included do
    let(:task_name) { self.class.top_level_description.sub(/\Arake /, "") }
    let(:tasks) { Rake::Task }

    # Make the Rake task available as `task` in your examples:
    subject(:task) { tasks[task_name] }
  end
end

RSpec.configure do |config|
  # Tag Rake specs with `:task` metadata or put them in the spec/tasks dir
  config.define_derived_metadata(file_path: %r{/spec/tasks/}) do |metadata|
    metadata[:type] = :task
  end

  config.include TaskExampleGroup, type: :task

  config.before(:suite) do
    Rails.application.load_tasks
  end
end

我的規范/支持/database_cleaner.rb

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

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

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

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

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

最后,規范:

require 'rails_helper'

describe "rake some:my_task", type: :task do

  # This test passes
  it 'preloads the Rails environment' do
    expect(task.prerequisites).to include 'environment'
  end

  # This test fails
  it 'creates AnotherModel' do
    my_hash = {foo => 'bar'}
    allow(MyClient::Event).to receive(:list).and_return(my_hash)

    expect { task.execute }.not_to raise_error

    expect(AnotherModel.count).to eq(1)
  end
end

問題是由於某種原因,執行此代碼會導致以下錯誤:

Failure/Error: AnotherModel.count
ActiveRecord::StatementInvalid:
  PG::InFailedSqlTransaction: ERROR:  current transaction is aborted, commands ignored until end of transaction block

rake 任務如下所示:

namespace :some do
  desc 'Parse stream'
  task my_task: :environment do |_t|
    cint_events['events'].each do |event|
      begin
        events = MyClient::Event.list(some_hash)
        events.each do |event|
          if some_condition
            # The test should check whether this object gets created
            AnotherModel.first_or_create_by(foo: some_hash['foo'])
          end
        end
      rescue => e
        # Log errors
      end
    end
  end
end

我試過運行:

RAILS_ENV=test rake db:drop db:create db:migrate

然后再次運行規范,但我不斷收到上述錯誤。 這可能是什么原因造成的?

提前致謝!

您將測試配置為在數據庫事務中運行,這是一件好事。 但是在你的 rake 任務中,你只會吃掉所有出現的錯誤:

rescue => e
  # Log errors
end

但是,某些錯誤可能仍會導致您的事務失敗和回滾。 所以我的猜測是,第一次調用數據庫時發生了一些嚴重的錯誤(例如,數據庫不知道列foo )。 之后,它會捕獲錯誤,並且您正在向已中止的事務添加一條語句 ( AnotherModel.count ),該事務失敗了。

因此,一個好的起點是檢查您的救援塊中e.message的值是什么

另請注意:盲目地挽救所有錯誤絕不是一個好主意,而且幾乎總是會導致奇怪和意外的行為。

當在測試環境中並且通過 ActiveRecord 的 SQL 查詢無法識別查詢中的字段時,似乎會發生此錯誤。 換句話說,您有一個范圍或試圖返回一些帶有錯誤數據庫列名的 ActiveRecord 關系。

請參閱此相關帖子: ActiveRecord::StatementInvalid: PG InFailedSqlTransaction

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM