method stubbing on before(:all)

亡梦爱人 提交于 2019-12-10 01:44:25

问题


require './spec/spec_helper'
require './bank'

describe Bank do
  context "#transfer" do
    before(:all) do
      @customer1 = Customer.new(500)
      customer2 = Customer.new(0)
      @customer1.stub(:my_money).and_return(1000)
      customer2.stub(:my_money).and_return(0)
      @transfer_message = Bank.new.transfer(@customer1, customer2, 2000)
    end 

    it "should return insufficient balance if transferred amount is greater than balance" do
      expect(@transfer_message).to eq("Insufficient funds")
    end 

    it "calls my_money" do
      expect(@customer1).to have_received(:my_money)
    end 
  end 
end

When I use before(:each) instead before(:all) it works. But if use before(:all) it throws error as undefined method proxy_for for nil:NilClass. I couldn't find out the reason. Could you please help me? Thanks in advance.


回答1:


Late to the party? Yeah, but wouldn't mind to drop my own one cent from what I discovered. I encountered a similar error while trying to stub a request in a RSpec.configure block so that the stub will only be available to examples I pass the config.around(:each, option) option to.

So, that means I was using the stub outside the scope of individual examples which is not supported by RSpec::Mocks here!. A work around is to use a temporary scope in the context.

So you have

before(:all) do
  RSpec::Mocks.with_temporary_scope do
    @customer1 = Customer.new(500)
    customer2 = Customer.new(0)
    @customer1.stub(:my_money).and_return(1000)
    customer2.stub(:my_money).and_return(0)
    @transfer_message = Bank.new.transfer(@customer1, customer2, 2000)
  end
end

HTH!




回答2:


before(:all) is not deprecated, but use of doubles from rspec-mocks in before(:all) is not supported. See the referenced issues in github issue for background.

The current master version of rspec-mocks, to be available with 3.0.0.beta2, will fail with the following error:

The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported.

Prior versions will generate the undefined method proxy_for ... error at the point of stubbing.




回答3:


This should work:

require "rspec/mocks/standalone"
before(:all) do



回答4:


I'm not sure if it's as canonical/best-practice as @El'Magnifico's answer using RSpec::Mocks.with_temporary_scope, but I found that by using an around hook instead of before, I was able to dynamically inject before blocks (and similar) into the example_group, resulting in them running alongside my test:

  • https://relishapp.com/rspec/rspec-core/docs/hooks/around-hooks

Example

# spec/spec_helper.rb
RSpec.configure do |config|
  # ..snip..
  config.include RequestForgerySpecHelper, type: :feature
  # ..snip..
end

# spec/support/request_forgery_spec_helper.rb
module RequestForgerySpecHelper
  def self.included(base)
    base.around(:all) do |ex|
      puts "around all start"

      ex.example_group.prepend_before do
        puts "around all inside prepend_before"
      end

      ex.example_group.append_after do
        puts "around all inside append_after"
      end

      ex.run

      puts "around all end"
    end
  end
end

Now if we assume our test already prints some logs before, after, and inside the test itself, our output looks like this:

around all start
around all inside prepend_before
inside spec file before
inside spec file test
inside spec file after
around all inside append_after
around all end

Because we are now dynamically injecting our before hook into the same context as our tests, we no longer see the following error:

before is not available from within an example (e.g. an it block) or from constructs that run in the scope of an example (e.g. before, let, etc). It is only available on an example group (e.g. a describe or context block)

Going Deeper

The ex parameter provided to the around hook is an instance of RSpec::Core::Example::Procsy, which gives access to the RSpec::Core::Example instance through the example attribute.

RSpec::Core::Example gives us access to the RSpec::Core::ExampleGroup associated with this test via the example_group method.

RSpec::Core::ExampleGroup gives us access to the DSL/methods allowing us to dynamically define before/after/let/etc blocks without triggering the not available from within an example error; as we can see by listing the methods in pry:

ls RSpec::Core::ExampleGroup
# RSpec::Core::Hooks#methods: after  append_after  append_before  around  before  hooks  prepend_after  prepend_before
# RSpec::Core::MemoizedHelpers::ClassMethods#methods: let  let!  subject  subject!
# RSpec::Core::ExampleGroup.methods:
#  add_example           currently_executing_a_context_hook?  define_nested_shared_group_method  describe                            ensure_example_groups_are_configured  fcontext   ffeature              fit                    fspecify                              include_examples       location                 parent_groups   run                       scenario   specify                          superclass_metadata    update_inherited_metadata  xexample   xspecify
#  before_context_ivars  declaration_locations                delegate_to_metadata               described_class                     example                               fdescribe  file_path             focus                  id                                    it                     metadata                 pending         run_after_context_hooks   set_it_up  store_before_context_ivars       top_level?             with_replaced_metadata     xfeature
#  children              define_example_group_method          descendant_filtered_examples       description                         example_group                         feature    filtered_examples     for_filtered_examples  idempotently_define_singleton_method  it_behaves_like        next_runnable_index_for  remove_example  run_before_context_hooks  set_ivars  subclass                         top_level_description  xcontext                   xit
#  context               define_example_method                descendants                        each_instance_variable_for_example  examples                              fexample   find_and_eval_shared  fscenario              include_context                       it_should_behave_like  ordering_strategy        reset_memoized  run_examples              skip       superclass_before_context_ivars  traverse_tree_until    xdescribe                  xscenario


来源:https://stackoverflow.com/questions/21235269/method-stubbing-on-beforeall

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!