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