开发者

Why is my rspec test failing?

Here's the test:

        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

Here's the error:

  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

I'm thinking the error might be somewhere in my data populator code:

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

Please let me know if I should reproduce any more of my code.

UPDATE: Here's where @attr 开发者_JAVA技巧is defined, at the top of the user_spec.rb file:

require 'spec_helper'

describe User do

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


Check to be sure that there isn't a block further up your user_spec.rb that is calling User.create in a before(:each) block with the same email address. If your blocks are nested incorrectly, you'll get this error. For example, in the Rails tutorial, it's easy to accidentally nest your describe "admin attribute" inside your describe "password encryption" block, which uses the same before(:each) code.


Try checking for existing users in the before block:

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

If that fails, then another user exists with the same email. This could be because another before block created a user with the same attributes, or that the test database was not correctly cleaned out after a failure. For the latter case, try running rake db:test:prepare, and then run the spec again.


before( :each ) is going to create a new user object from @attr. So if @attr isn't changing the values for its fields, and you have validations turned on to prevent duplicate, then on your 2nd test, the user object you created in the first test will collide with the one you are trying to create in the 2nd test.

There are other ways to go about testing your model without the database. For example, you can use test doubles to create and setup objects with exactly the data you want and then run your test to see if it behaves correctly. There is a [great book on RSpec, Cucumber and BDD] that could be a great source.

Edit: My apologies, I was confusing before(:each) with before(:all).


This does not seems to be ideal way of setting up test data. ie, using a rake task to populate the database.

A more standard unit testing and Rails practice would be to use both factory_girl or a test_fixture and transactional test fixture or database_cleaner gem.

Read a little bit about those, and they should be straight forward to use. They ensure, that each of your rspec test runs in isolation even when you run all of them together. That way, each test data for one test will not affect the other one.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜