我正在创建一个 Rails 应用程序(这方面相当新),并且我有一个不使用脚手架生成的客户端模型。我已经运行了“rake db:migrate”,并且正在使用“rake test:units”对模型进行单元测试,但是我在终端中得到了以下运行时错误的变体,几乎用于我所有的工厂测试。
test: Creating seven clients should show that all factories are properly created. (ClientTest):
NoMethodError: undefined method `destroy' for nil:NilClass
/Users/myUserName/Desktop/app_name/test/unit/client_test.rb:131:in `block (2 levels) in <class:ClientTest>'
我一直无法弄清楚错误是什么。我知道它无法识别客户端类,因此找不到 nil 的“销毁”方法。但是,我不确定如何解决它。
下面是我的模型代码,位于 app_name/app/models/client.rb
class Client < ActiveRecord::Base
# Callbacks
before_save :reformat_phone
# Relationships
has_many :assignments
has_many :counselors, :through => :assignments
has_many :interventions, :through => :assignments
# Validations
validates_presence_of :first_name, :last_name, :gender, :address, :city, :state, :zip, :phone, :active
validates_inclusion_of :gender, :in => %w[male female], :message => "is not an option"
validates_inclusion_of :marital_status, :in => %w[single married separated divorced], :message => "is not an option"
validates_inclusion_of :state, :in => %w[PA OH WV], :message => "is not an option"
validates_format_of :zip, :with => /^\d{5}$/, :message => "should be five digits long"
validates_format_of :phone, :with => /^\(?\d{3}\)?[-. ]?\d{3}[-.]?\d{4}$/, :message => "should be 10 digits (area code needed) and delimited with dashes only"
# Scopes
scope :active, where('active = ?', true)
scope :inactive, where('active = ?', false)
scope :alphabetical, order('last_name, first_name')
scope :receiving_gov_assistance, where('gov_assistance = ?', true)
scope :not_receiving_gov_assistance, where('gov_assistance = ?', false)
scope :male, where('gender = ?', 'male')
scope :female, where('gender = ?', 'female')
scope :by_marital_status, lambda { |status| where("marital_status = ?", status) }
scope :by_ethnicity, lambda { |race| where("ethnicity = ?", race) }
scope :employed, where('is_employed = ?', true)
scope :unemployed, where('is_employed = ?', false)
scope :veteran, where('is_veteran = ?', true)
scope :assigned, where('current_assignment != ?', nil)
scope :unassigned, where('current_assignment = ?', nil)
# Other methods
def name
"#{last_name}, #{first_name}"
end
def proper_name
"#{first_name} #{last_name}"
end
def current_assignment
curr_assignment = self.assignments.select{|a| a.end_date.nil?}
# alternative method for finding current assignment is to use scope 'current' in assignments:
# curr_assignment = self.assignments.current # will also return an array of current assignments
return nil if curr_assignment.empty?
curr_assignment.first # return as a single object, not an array
end
# Misc Constants
GENDER_LIST = [['Male', 'male'],['Female', 'female']]
STATES_LIST = [['Ohio', 'OH'],['Pennsylvania', 'PA'],['West Virginia', 'WV']]
# Callback code
# -----------------------------
private
def reformat_phone
phone = self.phone.to_s # change to string in case input as all numbers
phone.gsub!(/[^0-9]/,"") # strip all non-digits
self.phone = phone # reset self.phone to new string
end
end
这是我编写的测试,位于 app_name/test/unit/client_test.rb
require 'test_helper'
class ClientTest < ActiveSupport::TestCase
# Test relationships
should have_many(:assignments)
should have_many(:deacons).through(:assignments)
should have_many(:interventions).through(:assignments)
# Test basic validations
should validate_presence_of(:last_name)
should validate_presence_of(:first_name)
should validate_presence_of(:gender)
should validate_presence_of(:address)
should validate_presence_of(:city)
should validate_presence_of(:state)
should validate_presence_of(:zip)
should validate_presence_of(:phone)
should validate_presence_of(:active)
# Identity-based tests
# tests for gender
should allow_value("male").for(:gender)
should allow_value("female").for(:gender)
should_not allow_value(nil).for(:gender)
should_not allow_value(1).for(:gender)
should_not allow_value("seahorse").for(:gender)
should_not allow_value("I believe gender is a societal construct.").for(:gender)
# tests for ethnicity
should allow_value("Asian").for(:ethnicity)
should allow_value("Black").for(:ethnicity)
should allow_value("Hispanic").for(:ethnicity)
should allow_value("Latino").for(:ethnicity)
should allow_value("Native American").for(:ethnicity)
should allow_value("White").for(:ethnicity)
should_not allow_value(nil).for(:ethnicity)
should_not allow_value(1).for(:ethnicity)
should_not allow_value(true).for(:ethnicity)
should_not allow_value(0.5).for(:ethnicity)
# tests for marital status
should allow_value("single").for(:marital_status)
should allow_value("married").for(:marital_status)
should allow_value("separated").for(:marital_status)
should allow_value("divorced").for(:marital_status)
should_not allow_value("White").for(:marital_status)
should_not allow_value(nil).for(:marital_status)
should_not allow_value(1).for(:marital_status)
should_not allow_value(true).for(:marital_status)
should_not allow_value("I believe marriage is a societal construct.").for(:marital_status)
# Contact-based Tests
# tests for address
should allow_value("123 Example Lane").for(:address)
should allow_value("456 Another Street").for(:address)
should_not allow_value(true).for(:address)
should_not allow_value(101).for(:address)
should_not allow_value(nil).for(:address)
# tests for zip
should allow_value("12345").for(:zip)
should_not allow_value("bad").for(:zip)
should_not allow_value("1234").for(:zip)
should_not allow_value("123456").for(:zip)
should_not allow_value("12345-6789").for(:zip)
# tests for state
should allow_value("OH").for(:state)
should allow_value("PA").for(:state)
should allow_value("WV").for(:state)
should_not allow_value("bad").for(:state)
should_not allow_value("NY").for(:state)
should_not allow_value(10).for(:state)
should_not allow_value("CA").for(:state)
# tests for phone
should allow_value("4122683259").for(:phone)
should allow_value("412-268-3259").for(:phone)
should allow_value("412.268.3259").for(:phone)
should allow_value("(412) 268-3259").for(:phone)
should_not allow_value("2683259").for(:phone)
should_not allow_value("14122683259").for(:phone)
should_not allow_value("4122683259x224").for(:phone)
should_not allow_value("800-EAT-FOOD").for(:phone)
should_not allow_value("412/268/3259").for(:phone)
should_not allow_value("412-2683-259").for(:phone)
# Assistance-based tests
# tests for gov_assistance
should allow_value(true).for(:gov_assistance)
should allow_value(false).for(:gov_assistance)
should_not allow_value(150).for(:gov_assistance)
should_not allow_value("Yes").for(:gov_assistance)
# tests for is_employed
should allow_value(true).for(:is_employed)
should allow_value(false).for(:is_employed)
should_not allow_value(30000).for(:is_employed)
should_not allow_value("Movie theater usher").for(:is_employed)
# tests for is_veteran
should allow_value(true).for(:is_veteran)
should allow_value(false).for(:is_veteran)
should_not allow_value(nil).for(:is_veteran)
should_not allow_value("Marines").for(:is_veteran)
# Establish context
# Testing other methods with a context
context "Creating seven clients" do
setup do
@dan = FactoryGirl.create(:client)
@barney = FactoryGirl.create(:client, :last_name => "Saha", :first_name => "Barney", :active => false, :ethnicity => "Indian" )
@ryan = FactoryGirl.create(:client, :last_name => "Black", :first_name => "Ryan", :phone => "412-867-5309", :ethnicity => "White", :gov_assistance => true )
@joe = FactoryGirl.create(:client, :last_name => "Oak", :first_name => "Joseph", :ethnicity => "Asian", :is_employed => false )
@mary = FactoryGirl.create(:client, :last_name => "Clute", :first_name => "Mary", :gender => "female", :ethnicity => "White" )
@jon = FactoryGirl.create(:client, :last_name => "Carreon", :first_name => "Jon", :is_veteran => true )
@meg = FactoryGirl.create(:client, :last_name => "Smith", :first_name => "Megan", :ethnicity => "White", :gender => "female", :is_employed => false)
end
# and provide a teardown method as well
teardown do
@dan.destroy
@barney.destroy
@ryan.destroy
@joe.destroy
@mary.destroy
@jon.destroy
@meg.destroy
end
# test one of each factory
should "show that all factories are properly created" do
assert_equal "Tabrizi", @dan.last_name
assert @ryan.active
assert @joe.active
assert_equal "Mary", @mary.first_name
assert @jon.active
assert @meg.active
deny @barney.active
end
# test the callback is working 'reformat_phone'
should "shows that Ryan's phone is stripped of non-digits" do
assert_equal "4128675309", @ryan.phone
end
# test the scope 'alphabetical'
should "shows that there are seven clients in in alphabetical order" do
assert_equal ["Black", "Carreon", "Clute", "Oak", "Saha", "Smith", "Tabrizi"], Client.alphabetical.map{|s| s.last_name}
end
# test the scope 'active'
should "shows that there are six active clients" do
assert_equal 2, Client.active.size
assert_equal ["Black", "Carreon", "Clute", "Oak", "Smith", "Tabrizi"], Client.active.alphabetical.map{|s| s.last_name}
end
# test the scope 'inactive'
should "shows that there is one inactive client" do
assert_equal 1, Client.inactive.size
assert_equal ["Saha"], Client.inactive.alphabetical.map{|s| s.last_name}
end
# test the scope 'receiving_gov_assistance'
should "shows that there is one client receiving government assistance" do
assert_equal 1, Client.receiving_gov_assistance.size
assert_equal ["Black"], Client.receiving_gov_assistance.alphabetical.map{|s| s.last_name}
end
# test the scope 'not_receiving_gov_assistance'
should "shows that there are six clients not receiving government assistance" do
assert_equal 6, Client.not_receiving_gov_assistance.size
assert_equal ["Carreon", "Clute", "Oak", "Saha", "Smith", "Tabrizi"], Client.not_receiving_gov_assistance.alphabetical.map{|s| s.last_name}
end
# test the scope 'male'
should "shows that there are five male clients" do
assert_equal 6, Client.male.size
assert_equal ["Black", "Carreon", "Oak", "Saha", "Tabrizi"], Client.male.alphabetical.map{|s| s.last_name}
end
# test the scope 'female'
should "shows that there are two female clients" do
assert_equal 2, Client.female.size
assert_equal ["Clute", "Smith"], Client.female.alphabetical.map{|s| s.last_name}
end
# test the scope 'employed'
should "shows that there are five employed clients" do
assert_equal 5, Client.employed.size
assert_equal ["Black", "Carreon", "Clute", "Saha", "Tabrizi"], Client.employed.alphabetical.map{|s| s.last_name}
end
# test the scope 'unemployed'
should "shows that there are two unemployed clients" do
assert_equal 2, Client.unemployed.size
assert_equal ["Oak", "Smith"], Client.unemployed.alphabetical.map{|s| s.last_name}
end
# test the scope 'veteran'
should "shows that there is one employed clients" do
assert_equal 1, Client.veteran.size
assert_equal ["Carreon"], Client.veteran.alphabetical.map{|s| s.last_name}
end
# test the method 'name' #DONE
should "shows name as last, first name" do
assert_equal "Tabrizi, Dan", @dan.name
end
# test the method 'proper_name' #DONE
should "shows proper name as first and last name" do
assert_equal "Dan Tabrizi", @dan.proper_name
end
end
end
非常感谢您的帮助。如果有任何其他文件需要确定问题,请告诉我。抱歉,如果这很简单或太模糊,我是 Rails 开发的新手,我正在尽我所知使用术语
编辑
以下是我目前的客户工厂,在 app_name/test/factories.rb
FactoryGirl.define do
factory :client do
last_name "Tabrizi"
first_name "Dan"
gender "male"
ethnicity "Hispanic"
marital_status "single"
address "123 Example Lane"
city "Anytown"
state "PA"
zip "12345"
phone { rand(10 ** 10).to_s.rjust(10,'0') }
gov_assistance false
is_employed true
is_veteran false
active true
end
end