undefined方法first name =在rspec测试中使用factorygirl时

时间:2014-02-23 02:15:17

标签: ruby ruby-on-rails-4 factory-bot rspec-rails nomethoderror

http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html# 离开本教程目前。我正在添加另一个我从rails应用程序教程开始的项目。

我去创建我的模型规格     contact_spec.rb

require 'spec_helper'

describe Contact do 
it "has a valid factory" do
    FactoryGirl.create(:contact).should be_valid
end
it "is invalid without a firstname"
it "is invalid without a lastname"
it "returns a contact's full name as a string"  
end

工厂/ contacts.rb

require 'faker'

FactoryGirl.define do
    factory :contact do |f|
    f.firstname { Faker::Name.first_name }
    f.lastname { Faker::Name.last_name }
    end
end

我运行rspec并收到此错误:

    1) Contact has a valid factory
    Failure/Error: FactoryGirl.create(:contact).should be_valid
    NoMethodError:
    undefined method `firstname=' for #<Contact name: nil, email: nil, content: nil>
    # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'
    Finished in 0.22028 seconds
    4 examples, 1 failure, 3 pending

这是我的联系模式

 class Contact < ActiveRecord::Base
  has_no_table

  column :name, :string
  column :email, :string
  column :content, :string

  validates_presence_of :name
  validates_presence_of :email
  validates_presence_of :content
  validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
  validates_length_of :content, :maximum => 500

  def update_spreadsheet
    connection = GoogleDrive.login(ENV["GMAIL_USERNAME"], ENV["GMAIL_PASSWORD"])
    ss = connection.spreadsheet_by_title('Learn-Rails-Example')
     if ss.nil?
      ss = connection.create_spreadsheet('Learn-Rails-Example')
    end
    ws = ss.worksheets[0]
    last_row = 1 + ws.num_rows
    ws[last_row, 1] = Time.new
    ws[last_row, 2] = self.name
    ws[last_row, 3] = self.email
    ws[last_row, 4] = self.content
    ws.save
  end

end

和我的contactS_controller

class ContactsController < ApplicationController

  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(secure_params[:contact])
    if @contact.valid?
      @contact.update_spreadsheet
      UserMailer.contact_email(@contact).deliver
      flash[:notice] = "Message sent from #{@contact.name}."
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def secure_params
    params.require(:contact).permit(:name, :email, :content)
  end

end

我尝试更改:名称为:firstname,和:lastname并最终收到此新错误

1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::RecordInvalid:
       Validation failed: Email can't be blank, Email is invalid, Content can't be blank
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.22596 seconds
4 examples, 1 failure, 3 pending

Failed examples:

rspec ./spec/models/contact_spec.rb:4 # Contact has a valid factory

我的猜测是,当我参考:联系时,我没有正确定义。

修改 添加Faker :: Internet.email attr引发了一个新错误

 1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::RecordInvalid:
       Validation failed: Content can't be blank
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

所以我评论出validates_presence_of:content,column:content和validates_length_of:content并得到这个

 1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::Tableless::NoDatabase:
       Can't #create_record a Tableless object
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

所以似乎事情正在起作用,因为我应用它们或带走,我显然在我编写的代码与一个教程之间有很多冲突,并使用rspec factory_girl和faker添加此方法

编辑2 所以在添加了电子邮件和内容attr之后,我继续填写剩余的规格“无先生/姓氏无效”:

    describe Contact do 
            it "has a valid factory" do
        FactoryGirl.build(:contact).should be_valid
        end
        it "is invalid without a firstname" do 
            FactoryGirl.build(:contact, lastname: nil).should_not be_valid 
        end

         it "is invalid without a lastname" do 
            FactoryGirl.build(:contact, lastname: nil).should_not be_valid 
        end

        it "returns a contact's full name as a string"  
    end

我的测试没有错误传递:

  is invalid without a lastname
  has a valid factory
  is invalid without a firstname
  returns a contact's full name as a string (PENDING: Not yet implemented)

Pending:
  Contact returns a contact's full name as a string
    # Not yet implemented
    # ./spec/models/contact_spec.rb:15

Finished in 0.22146 seconds
4 examples, 0 failures, 1 pending

谢谢你sonnyhe2002让我通过这个!非常感谢!

5 个答案:

答案 0 :(得分:1)

您需要向工厂添加电子邮件attr

FactoryGirl.define do
  factory :contact do |f|
    f.firstname { Faker::Name.first_name }
    f.lastname { Faker::Name.last_name }
    f.email { Faker::Internet.email }
    f.content 'This is content'
  end
end

由于您使用的是has_no_table,我认为工厂无法将其保存到数据库中。

您应该使用'build'而不是'create'

FactoryGirl.build(:contact).should be_valid

答案 1 :(得分:0)

您确定数据库中有firstname列吗?确保db/schema.rb的{​​{1}}表格中包含firstname列,并确保您已运行contacts

答案 2 :(得分:0)

给出的错误非常具有自我描述性:您的emailcontent属性上有一些验证器,但您没有在Contact工厂中设置这些属性以使您的模型有效。

编辑:请将此添加到您的联系工厂:

f.email 'email@example.com'
f.content 'a content'

答案 3 :(得分:0)

在你的模特中:

validates_presence_of :name
validates_presence_of :email
validates_presence_of :content
validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
validates_length_of :content, :maximum => 500

因此,在创建FactoryGirl用户时,您需要考虑上述事实。您只处理电子邮件名称的存在,但还需要处理内容的存在,其长度必须少于500个字符

答案 4 :(得分:0)

FactoryGirl现在由FactoryBot代替。不赞成使用FactoryGirl。

FactoryBot版本5及更高版本在创建工厂时仅支持动态属性。

因此解决方案是:-

FactoryBot.define do factory :user do name { "Ron" } email { "ron@gmail.com" } password { "ronY123" } password_confirmation { "ronY123" } end end