私は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 の「destroy」メソッドが見つからないことを理解しています。しかし、私はそれを修正する方法がわかりません。
以下は、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