Rails 4: PG::InFailedSqlTransaction 使用 RSpec 测试 rake 任务时
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
我的spec/support/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
在你的 rescue 块中的值是什么.
另请注意:
盲目挽救所有错误绝不是一个好主意,而且几乎总是会导致奇怪和意外的行为。
此错误似乎发生在测试环境中,并且您通过 ActiveRecord 进行的 SQL 查询无法识别查询中的字段。换句话说,您有一个范围或正在尝试 return 一些 ActiveRecord 关系与错误的数据库列名。
查看相关内容post:
ActiveRecord::StatementInvalid: PG InFailedSqlTransaction
我目前正在尝试使用 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
我的spec/support/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
在你的 rescue 块中的值是什么.
另请注意: 盲目挽救所有错误绝不是一个好主意,而且几乎总是会导致奇怪和意外的行为。
此错误似乎发生在测试环境中,并且您通过 ActiveRecord 进行的 SQL 查询无法识别查询中的字段。换句话说,您有一个范围或正在尝试 return 一些 ActiveRecord 关系与错误的数据库列名。
查看相关内容post: ActiveRecord::StatementInvalid: PG InFailedSqlTransaction