2012-07-24 89 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,所以将会失败。自从发生这种情况,它将返回记录的最后一个错误,这就是为什么你会收到该错误。

相关问题