为什么在数据库事务中没有出现这些Rspec示例?

时间:2013-06-04 17:10:54

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

我正在我的应用程序中编写一个典型的测试,我通过表单创建模型并检查模型计数是否等于1.

测试失败,因为测试数据库中已有多条记录,每次运行测试时此计数都会增加。看起来每个例子都没有发生在事务中(正在回滚),就像它应该的那样,我不知道为什么。

我在spec_helper.rb文件中有这一行,该文件应该在事务中运行每个示例:

config.use_transactional_fixtures = true

这是我不断生成模型对象的规范:

require 'spec_helper'

describe "Admin artwork pages" do
  subject { page }
  let(:gallery) { FactoryGirl.create(:gallery) }

  describe "artwork creation" do
    context "with valid attributes" do
      it "creates new artwork" do
        visit admin_gallery_artworks_path(gallery_id: gallery.id)

        click_link 'Add new artwork'
        fill_in 'artwork_title', with: 'Still Life'
        click_button 'Create Artwork'

        page.should have_text 'Successfully created'
        Artwork.count.should eq 1
      end
    end
  end
end

以下是来自Rspec的错误消息:

Failures:

1) Admin artwork pages artwork creation with valid attributes creates new artwork
 Failure/Error: Artwork.count.should eq 1

   expected: 1
        got: 153

   (compared using ==)

编辑:我的spec_helper.rb文件的内容:

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

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

RSpec.configure do |config| 

# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"

# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true

# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false

# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
#     --seed 1234
config.order = "random"
# Include route helpers
config.include Rails.application.routes.url_helpers
#
# Take the FactoryGirl out of FactoryGirl.create
config.include FactoryGirl::Syntax::Methods

我正在使用Rails 4.0.0.rc1,Ruby 1.9.3,FactoryGirl和rspec-rails 2.13.0感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

事实证明,从rspec-rails 2.13.1开始支持Rails 4 - 我使用的是2.13.0。升级后,规范发生在他们应该的交易中。

感谢所有花时间发布帮助的人。

答案 1 :(得分:0)

我认为问题在于您编写测试的方式,而不是config.use_transactional_fixtures = true。专注于(compared using ==)

错误的底部

尝试使用期望的更改rspec语法

改变这个:

  click_button 'Create Artwork'

  page.should have_text 'Successfully created'
  Artwork.count.should eq 1

对此:

  expect { click_button 'Create Artwork' }.to change { Artwork, :count }.by(1)

  page.should have_text 'Successfully created'

如果有帮助,请告诉我

答案 2 :(得分:0)

您正在运行请求规范:当您调用visit时,测试中的代码将在服务器实例中运行(在同一进程中)。特别是这意味着它使用的是不同的线程。

因此,应用程序代码最终使用不同的数据库连接,并且由于事务是每个连接事物,因此当您的控制器将记录插入数据库时​​,不会使用任何事务。

有几种方法可以解决这个问题。一种是放弃rspec的事务夹具并使用database_cleaner gem。您可以对其进行设置,以便控制器和模型规范使用事务,但请求规范使用truncate强制清除表。

另一种方法是尝试强制规范代码和服务器代码使用相同的数据库连接,这样就省去了问题。您可以在this answer中看到此方法。根据我的经验,这很有效,直到你开始使用像poltergeist这样的capybara驱动程序,它会在页面上运行任何javascript并且你的页面会激活ajax请求。

我一直使用的方法是将活动记录连接池大小设置为1:只允许1个连接,这样每个人都将使用相同的连接。然后,您必须做一些工作以确保连接返回到池或您的规范只是挂起。

我刚刚将这些细节写成blog post,但简而言之,你需要

  • 在调用访问,点击等方法之前调用ActiveRecord::Base.clear_active_connections!
  • hack config.middleware.insert_before ActiveRecord::ConnectionAdapters::ConnectionManagement,以便在每次请求后清除连接(默认情况下,它不会在测试中执行此操作)。