Rspec + Postgresql9.1违反了not null约束



我正在运行rails 3.1.3与postgresql 9.1和Rspec测试。这是一个基于rails教程的测试应用程序,作为我学习rails的一部分。

我的问题是spec/models/employee_spec。rb试验。到目前为止,有34个例子,除了三个都通过了,他们失败了,因为一个非零约束。以下是失败的测试:

it "should create a new instance given valid attributes" do
    Employee.create!(@attr)   
  end (------ the Employee.create!(@attr) seems to be the problem)
it "should reject duplicate email addresses" do
    # Put an employee with a given email address into the database.
    Employee.create!(@attr) 
    employee_with_duplicate_email = Employee.new(@attr)
    employee_with_duplicate_email.should_not be_valid
  end
it "should reject email addresses identical up to case" do
    upcased_email = @attr[:email].upcase
    Employee.create!(@attr.merge(:email => upcased_email))
    employee_with_upcase_email = Employee.new(@attr)
    employee_with_upcase_email.should_not be_valid
  end

希望你们中的一个谁读这篇文章,如果它不是太长,可以给我一些指针,我如何解决这个问题。(我可以进入postgresql并改变属性,使其接受空值,但我想认为rspec应该能够处理非空约束)

好吧,谢谢你们所有人给我的帮助、指点和指导。

汤姆。

表的schema:

# == Schema Information
#
# Table name: employees
#
#  id                        :integer         not null, primary key
#  first_name                :string(255)     not null
#  last_name                 :string(255)     not null
#  mi                        :text
#  marital_status            :string(255)     not null
#  gender                    :string(255)     not null
#  birth_date                :date            default(Sat, 20 Aug 1949), not null
#  hire_date                 :date            not null
#  term_date                 :date
#  primary_position          :string(255)     not null
#  trained_position          :string(255)
#  email                     :string(255)     not null
#  active                    :boolean         default(TRUE), not null
#  address1                  :string(255)     not null
#  address2                  :string(255)
#  city                      :string(255)     not null
#  zip_code                  :string(255)     not null
#  state                     :string(255)     not null
#  emp_home_ph               :string(255)
#  emp_mobile_ph             :string(255)
#  emer_contact_first_name   :string(255)
#  emer_contact_last_name    :string(255)
#  emer_contact_relationship :string(255)
#  emer_contact_ph           :string(255)
#  created_at                :datetime
#  updated_at                :datetime
#

规范文件(~/spec/models/employee_spec.rb):

require 'spec_helper'
describe Employee do
  before(:each) do
     @attr = { :first_name => "Teress", :last_name => "Pottle", :mi => "null",  
    :marital_status => "Single", :gender => "Female", :birth_date => '1987-04-20',  
    :hire_date => '2002-01-01', :term_date => "null", :active => "true",  
    :primary_position => "Job Coach", :trained_position => "null", :email =>   
    "tpottle@example.com", :address1 => "1 First Ave", :address2 => "null", :city =>  
    "Frave", :zip_code => "54806", :state => "WI", :emp_home_ph => "null",  
    :emp_mobile_ph => "null", :emer_contact_first_name => "null",  
    :emer_contact_last_name => "null", :emer_contact_relationship => "null",  
    :emer_contact_ph => "null" }
   end
 it "should create a new instance given valid attributes" do
     Employee.create!(@attr)
 end
 it "should require a first_name" do
    no_first_name = Employee.new(@attr.merge(:first_name => ""))
    no_first_name.should_not be_valid
 end
 it "should reject first_name that is too long" do
   long_name = "a" * 26
   long_first_name = Employee.new(@attr.merge(:first_name => long_name))
   long_first_name.should_not be_valid
 end
 it "should require a last_name" do
   no_last_name = Employee.new(@attr.merge(:last_name => ""))
   no_last_name.should_not be_valid
 end
 it "should reject a last_name that is too long" do
   long_name = "a" * 26
   long_last_name = Employee.new(@attr.merge(:last_name => long_name))
   long_last_name.should_not be_valid
 end
 it "should require a marital_status" do
   no_marital_status = Employee.new(@attr.merge(:marital_status => ""))
   no_marital_status.should_not be_valid
 end
 it "should require a gender" do
   no_gender = Employee.new(@attr.merge(:gender => ""))
   no_gender.should_not be_valid
 end
 it "should require a birth_date" do
   no_birth_date = Employee.new(@attr.merge(:birth_date => ""))
   no_birth_date.should_not be_valid
 end
 it "should require a hire_date" do
   no_hire_date = Employee.new(@attr.merge(:hire_date => ""))
   no_hire_date.should_not be_valid
 end
 it "should require a primary_position" do
    no_primary_position = Employee.new(@attr.merge(:primary_position => ""))
    no_primary_position.should_not be_valid
 end
 it "should require a email" do
    no_email = Employee.new(@attr.merge(:email => ""))
    no_email.should_not be_valid
 end
 it "should require an 'active' setting" do
    no_active_setting = Employee.new(@attr.merge(:active => ""))
    no_active_setting.should_not be_valid
 end
it "should require an address1" do
    no_address1 = Employee.new(@attr.merge(:address1 => ""))
    no_address1.should_not be_valid
end
it "should require a city" do
   no_city = Employee.new(@attr.merge(:city => ""))
   no_city.should_not be_valid
end
it "should require a zip_code" do
   no_zip_code = Employee.new(@attr.merge(:zip_code => ""))
   no_zip_code.should_not be_valid
end
it "should require a state" do
   no_state = Employee.new(@attr.merge(:state => ""))
   no_state.should_not be_valid
end
it "should accept valid email addresses" do
   addresses = %w[user@foo.com THE_USER@foo.bar.org first.last@foo.jp]
     addresses.each do |address|
       valid_email_employee = Employee.new(@attr.merge(:email => address))
       valid_email_employee.should be_valid
    end
end
it "should reject invalid email addresses" do
   addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
      addresses.each do |address|
         invalid_email_employee = Employee.new(@attr.merge(:email => address))
         invalid_email_employee.should_not be_valid
      end
end
it "should reject duplicate email addresses" do
   # Put an employee with a given email address into the database.
   Employee.create!(@attr)
   employee_with_duplicate_email = Employee.new(@attr)
   employee_with_duplicate_email.should_not be_valid
end
it "should reject email addresses identical up to case" do
  upcased_email = @attr[:email].upcase
  Employee.create!(@attr.merge(:email => upcased_email))
  employee_with_upcase_email = Employee.new(@attr)
  employee_with_upcase_email.should_not be_valid
end
end

Employee类(~/app/models/employee.rb):

 class Employee < ActiveRecord::Base
  attr_accessor :first_name, :last_name, :mi, :marital_status, :gender, :birth_date,  
 :hire_date, :term_date, :primary_position, :trained_position, :email, :active,  
 :address1, :address2, :city, :zip_code, :state, :emp_home_ph, :emp_mobile_ph,  
 :emer_contact_first_name, :emer_contact_last_name, :emer_contact_relationship, 
 :emer_contact_ph
 email_regex = /([w+.]+)@[a-z0-9-.]+.[a-z]+/i
 date_regex = /^[0-9]{4}[-][0-9]{2}[-][0-9]{2}$/
 validates(:marital_status, :gender, :primary_position, :active, :address1, :city, 
 :zip_code, :state, :presence => true)
 validates(:first_name, :last_name, :presence => true, 
        :length => { :maximum => 25 })
 validates(:birth_date, :hire_date, :presence => true,
        :format => { :with => date_regex })
 validates(:email, :presence => true,
        :format => { :with => email_regex },
        :uniqueness => { :case_sensitive => false})
end

当我运行rspec:

时会发生什么?
loading autotest/rails_rspec2
/home/tom/.rvm/rubies/ruby-1.9.3-p0/bin/ruby -rrubygems -S /home/tom/.rvm/gems  
/ruby-1.9.3-p0@latest/gems/rspec-core-2.7.1/exe/rspec --tty  
'/home/tom/rails_projects/tracking /spec/controllers/employees_controller_spec.rb'   
'/home/tom/rails_projects/tracking/spec/controllers/pages_controller_spec.rb' '/home  
/tom/rails_projects/tracking/spec/models/employee_spec.rb' '/home/tom/rails_projects  
/tracking/spec/requests/layout_links_spec.rb'
........F.................FF......
Failures:
1) Employee should create a new instance given valid attributes
 Failure/Error: Employee.create!(@attr)
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", 
   "city", "created_at", "email", "emer_contact_first_name", 
   "emer_contact_last_name",  "emer_contact_ph", "emer_contact_relationship",
   "emp_home_ph", "emp_mobile_ph", "first_name", "gender", "hire_date", "last_name",
   "marital_status", "mi", "primary_position", "state", "term_date", 
   "trained_position", "updated_at", "zip_code")
    VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 
    $17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
    # ./spec/models/employee_spec.rb:42:in `block (2 levels) in <top (required)>'
2) Employee should reject duplicate email addresses
 Failure/Error: Employee.create!(@attr)
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", "city",
   "created_at", "email", "emer_contact_first_name", "emer_contact_last_name",
  "emer_contact_ph", "emer_contact_relationship", "emp_home_ph", "emp_mobile_ph",
  "first_name", "gender", "hire_date", "last_name", "marital_status", "mi",
  "primary_position", "state", "term_date", "trained_position", "updated_at", 
  "zip_code") 
   VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 
   $17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
   # ./spec/models/employee_spec.rb:140:in `block (2 levels) in <top (required)>'
3) Employee should reject email addresses identical up to case
 Failure/Error: Employee.create!(@attr.merge(:email => upcased_email))
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", "city",  
   "created_at", "email", "emer_contact_first_name", "emer_contact_last_name",
   "emer_contact_ph", "emer_contact_relationship", "emp_home_ph", "emp_mobile_ph",
   "first_name", "gender", "hire_date", "last_name", "marital_status", "mi",
   "primary_position", "state", "term_date", "trained_position", "updated_at",
   "zip_code") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14,  
   $15, $16,$17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
   # ./spec/models/employee_spec.rb:147:in `block (2 levels) in <top (required)>'
 Finished in 19.24 seconds
 34 examples, 3 failures
 Failed examples:
rspec ./spec/models/employee_spec.rb:41 # Employee should create a new instance given
valid attributes
rspec ./spec/models/employee_spec.rb:138 # Employee should reject duplicate email
addresses
rspec ./spec/models/employee_spec.rb:145 # Employee should reject email addresses
identical up to case

你的问题不是你的测试,你的问题是你的Employee类。您的类开始如下:

class Employee < ActiveRecord::Base
  attr_accessor :first_name, :last_name, :mi, :marital_status, :gender, :birth_date,  
   :hire_date, :term_date, :primary_position, :trained_position, :email, :active,  
   :address1, :address2, :city, :zip_code, :state, :emp_home_ph, :emp_mobile_ph,  
   :emer_contact_first_name, :emer_contact_last_name, :emer_contact_relationship, 
   :emer_contact_ph

,但您不需要或不想在这里使用attr_accessor。普通对象属性(attr_accessor创建)与ActiveRecord属性不同。ActiveRecord将检查表的结构,为数据库支持的属性创建自己的内部存储,并为这些属性创建一套accessor和mutator方法;在内部,ActiveRecord将使用那些访问器方法来查看对象中的内容。然后,使用attr_accessor将列声明为对象属性,attr_accessor创建自己的访问器和mutator方法来替换ActiveRecord的方法。结果是object.first_name将在object中寻找@first_name实例变量,但不会有这样的事情,Employee.create将在ActiveRecord的属性中设置first_name而不是 @first_name实例值。

解决方案是去掉类中的attr_accessor语句。然后阅读Rails指南与您的教程并行。

最新更新