1

我正在我的应用程序中编写一个典型的测试,我通过一个表单创建一个模型并检查模型计数是否等于 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 感谢您的帮助。

4

3 回答 3

4

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

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

于 2013-06-04T20:50:30.243 回答
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'

让我知道这是否有帮助

于 2013-06-04T19:55:08.923 回答
0

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

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

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

另一种方法是尝试强制规范代码和服务器代码使用相同的数据库连接,从而消除问题。您可以在这个答案中看到这种方法。以我的经验,在您开始使用水豚驱动程序(例如 poltergeist)之前,这非常有效,它将在页面上运行任何 javascript 并且您的页面会触发 ajax 请求。

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

前段时间我在博客文章中写了详细信息,但简而言之,您需要

  • 在调用ActiveRecord::Base.clear_active_connections!访问、点击等方法之前调用
  • hack config.middleware.insert_beforeActiveRecord::ConnectionAdapters::ConnectionManagement以便在每次请求后清除连接(默认情况下它不会在测试中这样做)。
于 2013-06-04T20:13:21.667 回答