为什么我的rspec测试失败了?

时间:2011-02-27 05:52:56

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

以下是测试:

        describe "admin attribute" do

        before(:each) do
          @user = User.create!(@attr)
        end

        it "should respond to admin" do
          @user.should respond_to(:admin)
        end

        it "should not be an admin by default" do
          @user.should_not be_admin
        end

        it "should be convertible to an admin" do
          @user.toggle!(:admin)
          @user.should be_admin
        end
      end

这是错误:

  1) User password encryption admin attribute should respond to admin
 Failure/Error: @user = User.create!(@attr)
 ActiveRecord::RecordInvalid:
   Validation failed: Email has already been taken
 # ./spec/models/user_spec.rb:128

我认为错误可能出现在我的数据填充程序代码中:

require 'faker'

namespace :db do
  desc "Fill database with sample data"
  task :populate => :environment do
    Rake::Task['db:reset'].invoke
    admin = User.create!(:name => "Example User",
                 :email => "example@railstutorial.org",
                 :password => "foobar",
                 :password_confirmation => "foobar")
    admin.toggle!(:admin)             
    99.times do |n|
      name  = Faker::Name.name
      email = "example-#{n+1}@railstutorial.org"
      password  = "password"
      User.create!(:name => name,
                   :email => email,
                   :password => password,
                   :password_confirmation => password)
    end
  end
end

如果我要再复制我的代码,请告诉我。

更新:这是定义@attr的位置,位于user_spec.rb文件的顶部:

require 'spec_helper'

describe User do

  before(:each) do
      @attr = { 
        :name => "Example User", 
        :email => "user@example.com",
        :password => "foobar",
        :password_confirmation => "foobar" 
      }
    end

4 个答案:

答案 0 :(得分:6)

检查以确保user_spec.rb中使用相同电子邮件地址的User.create阻止before(:each)中的describe "admin attribute"进一步阻止阻止。如果您的块嵌套不正确,您将收到此错误。例如,在Rails教程中,很容易意外地将describe "password encryption"嵌套在before(:each)块中,该块使用相同的{{1}}代码。

答案 1 :(得分:2)

尝试检查之前块中的现有用户:

before(:each) do
  User.count.should == 0
  @user = User.create!(@attr)
end

如果失败,则另一个用户存在相同的电子邮件。这可能是因为另一个块之前创建了具有相同属性的用户,或者在失败后未正确清除测试数据库。对于后一种情况,请尝试运行rake db:test:prepare,然后再次运行规范。

答案 2 :(得分:0)

before( :each )将从@attr创建一个新的用户对象。因此,如果@attr没有更改其字段的值,并且您已启用验证以防止重复,那么在第二次测试中,您在第一次测试中创建的用户对象将与您尝试创建的用户对象发生冲突第二次测试。

在没有数据库的情况下,还有其他方法可以测试您的模型。例如,您可以使用测试双精度来创建和设置具有所需数据的对象,然后运行测试以查看其行为是否正确。有一本关于RSpec,Cucumber和BDD的好书可能是一个很好的来源。

编辑:道歉,我对before(:each) before(:all)感到困惑。

答案 3 :(得分:0)

这似乎不是设置测试数据的理想方式。即,使用rake任务填充数据库。

更标准的单元测试和Rails实践是使用factory_girl或test_fixture和事务测试夹具或database_cleaner gem。

阅读一些有关这些的内容,他们应该直接使用。他们确保即使您将所有这些测试一起运行,您的每个rspec测试都会单独运行。这样,一次测试的每个测试数据都不会影响另一个测试数据。