Em 29-04-2011 13:15, David Kahn escreveu:


On Thu, Apr 28, 2011 at 8:03 PM, Pat Maddox <patmad...@me.com <mailto:patmad...@me.com>> wrote:

    On Apr 28, 2011, at 4:37 PM, David Kahn wrote:

    > I am a bit new to mocking. I am trying to stub the
    ActiveMerchant::Billing::PaypalGateway#authorize method but not
    clear how to do it. This is my code and spec.
    >
    > This is the pertinent code:
    >
    > module Payment
    >   def gateway
    >     ActiveMerchant::Billing::PaypalGateway.new(
    >       ...
    >     )
    >   end
    >
    >   def authorize_payment(payment_info, associated_record_type,
    associated_record_id)
    >       gateway.authorize(payment_info.amount ......
    >   end
    >
    > I tried this:
    >
    
ActiveMerchant::Billing::PaypalGateway.should_receive(:authorize).and_return(authorize_payment_success_response)

    This is setting an expectation on the PaypalGateway object (which
    is a class!). But when you call PaypalGateway.new, you get back an
    instance - which is where you want to set the expectation. So what
    you really need to stub is something that looks more like an
    instance...you'd start off with:

gateway = stub('gateway')
    gateway.should_receive(:authorize)

    and next you can either stub PaypalGateway.new:
    ActiveMerchant::Billing::PaypalGateway.stub(:new).and_return gateway

    or what I'd more likely do:
    Payment.stub(:gateway).and_return gateway



Thanks Pat, this worked great and I think helping get my head around doing this.

I do have one additional question... I am testing a module here, and noticed that I had to both include the module (Payment) *and* in my spec call Payment#authorize_payment to get things working with the stub.

It seems kind of strange as if I did not include the module at the top, then I would get 'undefined method `authorize_payment' for Payment:Module' when called in the spec, which makes sense. But what does not make sense is that when I do include the Module at the top, I still have to call Payment#authorize_payment and not just authorize_payment to get the stub to take (the test passes in both cases, when not explicitly declaring Payment#... the mock does not take).

So it seems that it is as if there are two versions of Payment module --- one which is explicitly connected via the rspec stub, and the other which is the native. Once I stub Payment explicitly, I must explicitly declare it on my calls, otherwise it goes to the native code. Is this correct?

I thought if I just removed the line 'Payment.stub(:gateway).and_return(gateway)' that I would not have to call Payment#authorize.... and instead use authorize... but again, in this case the mock does not take.

Anyway, I have things working (as below), but interested in why this is so.

require 'spec_helper'
include Payment

describe Payment do

  before(:each) do
    gateway = stub('gateway')
    Payment.stub(:gateway).and_return(gateway)
gateway.stub!(:authorize).and_return(gateway_authorize_success_response)
  end

  it "should authorize payment with paypal using a valid card" do
response = Payment.authorize_payment(payment_info_success, 'Bet', 1000)
    ...
  end

I.E., why does this not hit the stub:

  it "should authorize payment with paypal using a valid card" do
    response = authorize_payment(payment_info_success, 'Bet', 1000)
    ...
  end

That is what happens in Rspec behind the scenes:

module A
  def test
     1
  end
end

include A

puts test # 1
puts A.test # 1
puts singleton_methods.include?(:test) # false
puts A.singleton_methods.include?(:test) # false

class << A
   def test
       2
   def
end

puts test # 1
puts A.test # 2
puts singleton_methods.include?(:test) # false
puts A.singleton_methods.include?(:test) # true

If you don't know very much about singleton classes (some people call them anonymous classes), you can take a look at these articles:

http://www.contextualdevelopment.com/articles/2008/ruby-singleton
http://ola-bini.blogspot.com/2006/09/ruby-singleton-class.html

Hope that helps understanding why you can't include a mocked module in your spec (actually you can, but it won't work as expected...)

Cheers,

Rodrigo.

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to