为什么rails不会在运行之间重置测试数据库

时间:2014-06-12 23:54:22

标签: ruby-on-rails testing factory-bot minitest

rails代码库中有注释表明应该在运行之间重置测试数据库

rake -T

rake test:all                           # Run tests quickly by merging all types and not resetting db
rake test:all:db                        # Run tests quickly, but also reset db

配置/ database.yml的

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:

对我来说,情况似乎并非如此。

我正在使用工厂女孩生成测试模型,这里是一个示例工厂

FactoryGirl.define do
  factory :podcast do
    sequence(:title)     { |n| "Podcast #{n}" }
    sequence(:feed_url)  { |n| "http://podcast.com/#{n}" }
  end
end

播客应该有一个独特的feed_url,因此我验证了它在模型中的唯一性。

class Podcast < ActiveRecord::Base
  validates :feed_url, uniqueness: true, presence: true
end

test_helper.rb I lint所有工厂

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

FactoryGirl.lint

我的测试创建一个播客,使用相同的名称构建另一个播客,然后断言第二个播客 无效。

require 'test_helper'

describe Podcast do
  describe '#feed_url' do
    it 'must be unique' do
      podcast = create(:podcast)
      new_podcast = build(:podcast, feed_url: podcast.name)

      assert_invalid podcast, :feed_url, 'has already been taken'
    end
  end
end

第一次运行测试时,它会毫无错误地执行,测试全部通过。 第二次运行测试时,Factory Girl lint失败,因为播客feed_url已经被拍摄。

为什么不在运行之间重建测试数据库?

3 个答案:

答案 0 :(得分:8)

数据库未重置的原因是您在rails提供的数据库事务之外运行测试。 ActiveSupport::TestCase类是所有rails测试的基础。 ActiveRecord将此测试数据库事务添加到此类。此事务将在每次测试后重置数据库。但是您没有使用ActiveSupport::TestCase运行测试,而是使用Minitest::Spec运行测试,而minitest/autorun未配置为运行事务。

最简单的解决方案是在您的Gemfile中添加minitest-rails,并将test_helper.rb文件中的require从minitest/rails更改为{{1}}。如果您希望添加自己对Minitest规范DSL的支持,可以使用this article作为起点。

答案 1 :(得分:6)

我们有一个更复杂的FactoryGirl设置,用一些规范项目准备我们的数据库,但我认为您可以将此代码直接放在test_helper.rb中以确保数据库已清空:

# Destroy all models because they do not get destroyed automatically
(ActiveRecord::Base.connection.tables - %w{schema_migrations}).each do |table_name|
  ActiveRecord::Base.connection.execute "TRUNCATE TABLE #{table_name};"
end

或者,在每次运行之前运行rake db:test:prepare

你也可以使用宝石,但我没有任何使用经验:http://rubygems.org/gems/database_cleaner

答案 2 :(得分:1)

您是否有其他工厂可能通过协会创建播客?

FactoryGirl linting构建每个工厂并检查其有效性,如果另一个工厂将播客作为关联,它将创建一个播客记录。

FactoryGirl建议在运行linting后清除数据库。他们在示例中使用database_cleanerhttps://github.com/thoughtbot/factory_girl/blob/2bf15e45305ac03315cf2ac153db523d3ce89ce1/GETTING_STARTED.md#linting-factories