使用SQLite运行guard时出现异常的事务异常

时间:2014-09-01 14:27:25

标签: ruby-on-rails rspec guard

只需运行rspec,我的所有测试都会持续通过。我已经安装了Guard,现在我遇到了不一致的问题。具体来说,如果我对控制器进行了更改,其规范可能会失败1或3或6.它们似乎植根于数据库锁定,导致其他测试使用不一致的数据。

我试图找到类似的问题,但我想出的只是rspec和sqlite解决方案。我确信这是一个Guard配置问题,因为正如我所说,测试是从命令行运行的。

以下是我在同一个文件中进行一些更改并且每次都得到不同结果的示例:

]2;[RSpec results] Failed
10:20:05 - INFO - Running: spec/controllers/V1/players_controller_spec.rb
..
  An error occurred in an after hook
    ActiveRecord::StatementInvalid: SQLite3::IOException: disk I/O error: DELETE FROM "player_connections"
    occurred at /Users/joe/.rvm/gems/ruby-2.1.1/gems/sqlite3-1.3.9/lib/sqlite3/statement.rb:108:in `step'

F...

Failures:

  1) V1::PlayersController GET players with failing auth fails when incorrect token is passed
     Failure/Error: FactoryGirl.create :client, name: "joe", auth_token: "bad token!!"
     ActiveRecord::StatementInvalid:
       SQLite3::SQLException: cannot rollback - no transaction is active: rollback transaction
     # ./spec/controllers/V1/players_controller_spec.rb:14:in `block (3 levels) in <top (required)>'

Finished in 1.26 seconds (files took 4.33 seconds to load)
6 examples, 1 failure

Failed examples:

rspec ./spec/controllers/V1/players_controller_spec.rb:13 # V1::PlayersController GET players with failing auth fails when incorrect token is passed

Randomized with seed 45348

]2;[RSpec results] Failed
10:24:38 - INFO - Running: spec/controllers/V1/players_controller_spec.rb
FF..F.

Failures:

  1) V1::PlayersController POST player should default score to 0
     Failure/Error: post :create, format: :json, player: FactoryGirl.attributes_for(:player)
     ActiveRecord::StatementInvalid:
       SQLite3::SQLException: cannot rollback - no transaction is active: rollback transaction
     # ./app/controllers/v1/players_controller.rb:18:in `create'
     # ./spec/controllers/V1/players_controller_spec.rb:59:in `block (3 levels) in <top (required)>'

  2) V1::PlayersController POST player should create a new player
     Failure/Error: let!(:client) { FactoryGirl.create :client, name: "joe", auth_token: "asdfasdfasdfasdfasdfasdf" }
     ActiveRecord::StatementInvalid:
       SQLite3::SQLException: cannot rollback - no transaction is active: rollback transaction
     # ./spec/controllers/V1/players_controller_spec.rb:50:in `block (3 levels) in <top (required)>'

  3) V1::PlayersController GET players with failing auth fails when no token exists in client record
     Failure/Error: FactoryGirl.create :client, name: "joe"
     ActiveRecord::StatementInvalid:
       SQLite3::SQLException: cannot rollback - no transaction is active: rollback transaction
     # ./spec/controllers/V1/players_controller_spec.rb:21:in `block (3 levels) in <top (required)>'

Finished in 0.61151 seconds (files took 3.81 seconds to load)
6 examples, 3 failures

Failed examples:

rspec ./spec/controllers/V1/players_controller_spec.rb:57 # V1::PlayersController POST player should default score to 0
rspec ./spec/controllers/V1/players_controller_spec.rb:52 # V1::PlayersController POST player should create a new player
rspec ./spec/controllers/V1/players_controller_spec.rb:20 # V1::PlayersController GET players with failing auth fails when no token exists in client record

Randomized with seed 5752

]2;[RSpec results] 6 examples, 3 failures in 0.6115 seconds
ain)> 

我认为我的Guardfile就是你启动守卫时的例子:

require 'active_support/inflector'

# A sample Guardfile
# More info at https://github.com/guard/guard#readme

# Note: The cmd option is now required due to the increasing number of ways
#       rspec may be run, below are examples of the most common uses.
#  * bundler: 'bundle exec rspec'
#  * bundler binstubs: 'bin/rspec'
#  * spring: 'bin/rsspec' (This will use spring if running and you have
#                          installed the spring binstubs per the docs)
#  * zeus: 'zeus rspec' (requires the server to be started separetly)
#  * 'just' rspec: 'rspec'
guard :rspec, cmd: 'bundle exec rspec' do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }

  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$})          { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  watch('spec/rails_helper.rb')                       { "spec" }

  # Capybara features specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$})     { |m| "spec/features/#{m[1]}_spec.rb" }

  # Turnip features and steps
  watch(%r{^spec/acceptance/(.+)\.feature$})
  watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$})   { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end

包括spec文件:

describe V1::PlayersController, type: :controller do

  before :each do
    controller.request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials('asdfasdfasdfasdfasdfasdf')
  end

  after :each do
    ActiveRecord::Base.subclasses.each(&:delete_all)
  end

  describe "GET players with failing auth" do

    it 'fails when incorrect token is passed' do
      FactoryGirl.create :client, name: "joe", auth_token: "bad token!!"

      get :index, format: :json
      expect(response).not_to be_successful
    end

    it 'fails when no token exists in client record' do
      FactoryGirl.create :client, name: "joe"

      get :index, format: :json
      expect(response).not_to be_successful
    end

  end
  describe "GET players with proper auth" do

    let!(:player_before_transact_points) { FactoryGirl.create :player, name: "Sam", default_pull_rate: 105 }
    let!(:player_2) { FactoryGirl.create :player, name: "Ma", default_pull_rate: 125 }
    let!(:client) { FactoryGirl.create :client, name: "joe", auth_token: "asdfasdfasdfasdfasdfasdf" }

    it "is authenticated" do

      get :index, format: :json
      expect(response).to be_successful
    end

    it "returns all players" do

      get :index, format: :json
      body = JSON.parse(response.body)
      power_up_names = body.map { |m| m["name"] }
      expect(power_up_names).to match_array(["Sam", "Ma"])
    end
  end

  describe "POST player" do
    let!(:client) { FactoryGirl.create :client, name: "joe", auth_token: "asdfasdfasdfasdfasdfasdf" }

    it "should create a new player" do

      expect { post :create, format: :json, player: FactoryGirl.attributes_for(:player) }.to change(V1::Player, :count).by(1)
    end

    it "should default score to 0" do

      post :create, format: :json, player: FactoryGirl.attributes_for(:player)
      expect(V1::Player.last.score).not_to be_nil
      expect(V1::Player.last.score).to eq 0
    end
  end

end

2 个答案:

答案 0 :(得分:1)

我有类似的问题,因为我没有意识到我有两个保护进程在运行。因此,请确保只有一个进程正在访问数据库。

答案 1 :(得分:0)

我创建了一个新的RAILS_ENV,名为“ci&#39;并在其中运行Guard。看起来这个问题可能是RubyMine特有的。请参阅@ justingordon更详细的答案:

Is it impossible to use Guard with RubyMine?