检查user.should be_valid时RSpec测试失败

时间:2013-08-09 19:01:24

标签: ruby-on-rails rspec

我不熟悉测试,也无法弄清楚为什么会失败:

我有一个测试

require 'spec_helper'
require 'cancan/matchers'

describe User do
  subject(:user) { User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female') }

it "should be valid with a name, goal, password, password_confirmation, experience_level, and gender" do
  user.should be_valid
end

我认为这应该通过。我可以通过站点前端创建用户,但是我收到以下失败消息:

1) User should be valid with a name, goal, password, password_confirmation, experience_level, and gender
     Failure/Error: subject(:user) { User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female') }
     RuntimeError:
       Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
     # ./app/models/user.rb:32:in `add_initial_program'
     # ./spec/models/user_spec.rb:5:in `block (2 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:13:in `block (2 levels) in <top (required)>'

编辑:

添加用户模型:

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable, :omniauthable,
         :recoverable, :rememberable, :trackable, :validatable, :token_authenticatable

  before_save :ensure_authentication_token

  attr_accessible :email, :password, :password_confirmation, :remember_me, :goal_id, :experience_level_id, :gender, :role, :name, :avatar, :remote_avatar_url, :authentication_token, :measurement_units

  validates :goal_id,                 presence: :true
  validates :experience_level_id, presence: :true 
  validates :gender,                    presence: :true

  before_create :add_initial_program, :assign_initial_settings

protected

  def add_initial_program
    prog_id = Program.for_user(self).first.id
    self.user_programs.build( :cycle_order => 1, :group_order => 1, :workout_order => 1, :program_id => prog_id)
  end

第32行是:prog_id = Program.for_user(self).first.id

和引用的方法:

def self.for_user(user)
  where(:goal_id => user.goal_id, :experience_id => user.experience_level_id, :gender => user.gender)   
end

1 个答案:

答案 0 :(得分:1)

prog_id = Program.for_user(self).first.id表示“获取与此用户关联的第一个程序的ID”。根据我们所看到的情况,我们可以推断Program.for_user(self).first为零,并且在此nil上调用id方法。您确定在测试数据库中保存了一个与您在测试中创建的用户相关联的程序模型吗?您似乎无法在任何地方创建此模型,并且根据您的代码,在您尝试创建用户之前必须有相关的程序。

编辑:

您可以在主题块中初始化程序,如下所示:

subject(:user) do 
    Program.create!(#whatever attributes are appropriate)
    User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
end

块中的最后一个值是主题块的相关返回值,因此只要块返回User模型,即使块中有多个语句,事情也应该没问题。对我来说,这是最干净的初始化选项,您可以单独更改测试,因为很明显用户和程序紧密绑定在一起,这样,为了拥有一个有效的用户,您首先必须拥有一个关联的程序。我认为如果一个程序不存在,那么在User模型中创建一个创建程序的逻辑会更好(你可能想查看查询方法#first_or_create),但是块内的多个语句应该可以工作现在。