0

作成時にActiveMerchantで支払いを処理することを含む予約モデルの作成をテストしようとしています。

支払い処理の初期設定には、ActiveMerchantRailscastのフォローが含まれていました。支払いはアプリ内で正常に機能しています。(http://railscasts.com/episodes/145-integrating-active-merchant

ファクトリ内および独自の":valid_credit_card"ファクトリ内でcredit_cardオブジェクトを作成してみました...Reservation

基本的なテストは、予約を作成できることを確認することだけです。試験結果:

1) Reservation should have a valid factory
 Failure/Error: @current_reservation = Factory.create(:reservation)
 NoMethodError:
 undefined method `credit_card=' for #<Reservation:0xb5f6173c>
 # ./spec/models/reservation_spec.rb:11

予約は、reservation_setsを介してユーザーとhas_many部屋に属します

Factory.define :reservation do |f|
  f.association :user
  f.rooms { |a| [a.association(:room)] }
  f.arrival Time.now + 2.weeks
  f.nights  2
  f.phone "555-123-1234"
  f.credit_card :valid_credit_card
end

Factory.define :valid_credit_card, :class => ActiveMerchant::Billing::CreditCard do |f|
  expiration_date = Time.zone.now + 1.year  
  f.type "visa"
  f.number "4111111111111111"
  f.verification_value "333"
  f.month expiration_date.strftime("%m")
  f.year expiration_date.strftime("%y")
  f.first_name "Bob"
  f.last_name "Smith"
end

そしてspec/models/reservation_spec.rb。@credit_card Factory.buildを使用すると、credit_cardの「保存」に関するエラーが発生します。

行f.credit_card:valid_credit_cardを削除すると、にリストされ:month ていてもNoMethodErrorが発生します。アプリ内での予約の作成は機能します。:monthattr_accessor

  1) Reservation should have a valid factory
     Failure/Error: @current_reservation = Factory.create(:reservation)
     NoMethodError:
       undefined method `month' for nil:NilClass

describe Reservation do
  before :each do
    @smith = Factory.create(:user)
    @room = Factory.create(:room)
    #@credit_card = Factory.build(:valid_credit_card) 
  end
  it "should have a valid factory" do
    @current_reservation = Factory.create(:reservation)
    @current_reservation.should be_valid
  end
end

私は何を見落としている/間違っているのですか...?

予約モデルの抜粋

class Reservation < ActiveRecord::Base
  # relationships
  belongs_to :user
  has_many :reservation_sets, 
       :dependent => :destroy
  has_many :rooms, 
           :through => :reservation_sets
  has_many :transactions,
           :class_name => 'ReservationTransaction',
           :dependent => :destroy

  attr_accessor :card_number, :card_verification, :card_expires_on, :card_type, :ip_address, :rtype, :month, :year
  # other standard validations
  validate :validate_card, :on => :create

  # other reservation methods...
  # gets paid upon reservation creation
  def pay_deposit
    # Generate active merchant object

    ReservationTransaction.gateway = 
      ActiveMerchant::Billing::AuthorizeNetGateway.new({
        :login => rooms[0].user.gateway_login,
        :password => rooms[0].user.gateway_password
      }) 

    response = ReservationTransaction.gateway.purchase(deposit_price_in_cents, credit_card, purchase_options)
    t = transactions.create!(:action => "purchase", :amount => deposit_price_in_cents, :response => response)
    if response.success?
      update_attribute(:reserved_at, Time.now)
      # update state
      payment_captured!
    else
      transaction_declined!
      errors.add :base, response.message
    end
    t.card_number = credit_card.display_number
    t.save!
    response.success?
  end

  def validate_card
    unless credit_card.valid?
      credit_card.errors.full_messages.each do |message|
        errors.add :base, message #_to_base message
      end
    end
  end

  def credit_card
    @credit_card ||= ActiveMerchant::Billing::CreditCard.new(
      :type               => card_type,
      :number             => card_number,
      :verification_value => card_verification,
      :month              => card_expires_on.month,
      :year               => card_expires_on.year,
      :first_name         => first_name,
      :last_name          => last_name
    )
  end

そして、予約コントローラーからの作成アクション

  def create
    @reservation = Reservation.new(params[:reservation])
    @reservation.arrival = session[:arrival]
    @reservation.nights = session[:nights]
    @reservation.number_kids = session[:number_kids]
    @reservation.number_adults = session[:number_adults]
    session[:creating_reservation] = 1
    @reservation.user_id = @reservation.rooms[0].user_id
    session[:owner] = @reservation.user_id
    @rooms = Room.all
    @reservation.ip_address = request.remote_ip         

    # get room owner...
    @owner = User.find(@reservation.user_id) 
    respond_to do |format|
      if @reservation.save
        if @reservation.pay_deposit
          #set cc...
          @reservation.transactions[0].card_number = @reservation.send(:credit_card).display_number
          ReservationMailer.reservation_created(@reservation).deliver
          ReservationMailer.reservation_notice(@reservation).deliver
          session[:arrival] = nil
          session[:reservation_id] = @reservation.id
          if @owner 
            thanks_path = "#{@owner.permalink}/reservations/#{@reservation.id}" 
          else
            thanks_path = @reservation
          end
          format.html { redirect_to @reservation, :notice => 'Reservation was successfully created.' }
          format.json { render :json => @reservation, :status => :created, :location => @reservation }
          # also trigger email sending or wherever that is 
          # receipt email and order notification
          # 
        else
           # set flash or show message problem w/ transaction 

           format.html { render :action => "new" }
        end
      else
        format.html { render :action => "new" }
        format.json { render :json => @reservation.errors, :status => :unprocessable_entity }
      end
    end
  end
4

1 に答える 1

0

値を割り当てようとしているように見えますが、実際にはクラス アクセサーcredit_cardがありません。そのため、どこに電話しようとしても機能しません。f.credit_card :valid_credit_card

f.credit_card :valid_credit_card工場からを削除し、rspec stubsの使用を検討すると、rspec テストで次のようなことができます。

mock_cc = ActiveMerchant::Billing::CreditCard.new(
      :type               => card_type,
      :number             => card_number,
      :verification_value => card_verification,
      :month              => card_expires_on.month,
      :year               => card_expires_on.year,
      :first_name         => first_name,
      :last_name          => last_name
    )

Reservation.stub(:credit_card).and_return(mock_cc)

これにより、モデルがcredit_cardそれを呼び出したときに、モックされたオブジェクトが返されます。

于 2012-12-20T02:38:58.823 に答える