2012-07-24 88 views
1

我正在創建一個Rails應用程序(相當新),並且我有一個客戶端模型,而不使用腳手架生成。我已經運行了'rake db:migrate',並且我正在用'rake test:units'對模型進行單元測試,但是在幾乎所有的工廠測試中,我都會在終端中看到以下運行時錯誤的變化。「NoMethodError:undefined method'destroy'for nil:NilClass」When Unit Testing Rails Model

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>' 

我一直無法弄清楚錯誤是什麼。我明白它不承認客戶端類,因此它無法找到零的'銷燬'方法。但是,我不確定如何解決它。

下面是我的模型代碼,位於APP_NAME /應用/型號/ 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 /測試/單位/ 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 
+0

什麼是131? – Dougui 2012-07-24 14:00:08

+0

你能提供你的':client'工廠的代碼嗎? – 2012-07-24 14:16:37

+1

嘗試移除您的「拆解」塊。 'FactoryGirl應該爲你做.' – 2012-07-24 14:20:31

回答

0

希望你對執行單獨的測試數據庫測試,因此它是安全的:

teardown do 
    Client.destroy_all 
end 
+0

不幸的是,現在我遇到了另一個錯誤 '測試:創建7個客戶端應該顯示所有工廠都已正確創建。 (ClientTest): LoadError:期望的/Users/myUserName/Desktop/app_name/app/models/deacon.rb來定義Deacon' Deacon是我的另一個模型(在上面的模型代碼中用它代替輔導員)。所以它期待着Deacon模型,但我只是在爲客戶端進行測試(除了客戶端之外,我還評論過所有其他測試,只是爲了處理這個問題)。任何想法可能是什麼問題? – joshingmachine 2012-07-24 15:25:18

+0

混淆更多,並得到它的工作。它最終是由於我所做的其他事情,但改變拆解是關鍵。謝謝你的幫助。 – joshingmachine 2012-07-24 16:27:46

+1

歡迎您!但正如其他人所建議的那樣,在理想情況下應該刪除'拆卸'方法,因爲FactoryGirl應該在測試後執行事務創建和回滾。 – 2012-07-24 18:23:57

0

像西蒙建議,嘗試註釋掉或消除你的拆解。通常在這些情況下,拆解會掩蓋真正的錯誤,因爲它會編譯所有代碼並嘗試啓動銷燬方法,因爲您的工廠將返回nil,所以將會失敗。自從發生這種情況,它將返回記錄的最後一個錯誤,這就是爲什麼你會收到該錯誤。

相關問題