On Fri, Apr 29, 2011 at 10:05 PM, Rodrigo Rosenfeld Rosas < lboc...@yahoo.com.br> wrote:
> Em 29-04-2011 13:15, David Kahn escreveu: > > > > On Thu, Apr 28, 2011 at 8:03 PM, Pat Maddox <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...) > Thanks Rodrigo... I think I see it. In the end I have discovered that if I want to mock a module, rather than going directly I need to stub out methods in the class I am testing which call the module and this seems to work, otherwise (and I am not sure if this is exactly the case you are explaining), but certainly it 'does not work as expected'. > > Cheers, > > Rodrigo. > > > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users