方法存根之前(:全部)

时间:2014-01-20 13:23:24

标签: rspec rspec-rails

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

当我使用before(:each)代替before(:all)时,它有效。但是如果使用before(:all),它会将错误抛出为undefined method proxy_for for nil:NilClass。我找不出原因。请你帮助我好吗?提前谢谢。

4 个答案:

答案 0 :(得分:8)

不推荐使用

before(:all),但不支持在before(:all)中使用来自rspec-mocks的双精度数。有关背景,请参阅github issue中引用的问题。

当前master版本的rspec-mocks将与3.0.0.beta2一起使用,将失败,并显示以下错误:

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

以前的版本会在存根时生成undefined method proxy_for ...错误。

答案 1 :(得分:7)

晚会?是的,但是我不介意从我发现的东西中减去一分钱。我在尝试在RSpec.configure块中存根请求时遇到了类似的错误,因此存根仅对我传递config.around(:each, option)选项的示例可用。

因此,这意味着我在RSpec::Mocks here不支持的个别示例范围之外使用存根!解决方法是在上下文中使用临时范围。

所以你有

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 :(得分:5)

这应该有效:

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

答案 3 :(得分:0)

我不确定使用@El'Magnifico's answer是否像RSpec::Mocks.with_temporary_scope一样规范/最佳实践,但是我发现通过使用around钩子而不是before,我能够向before中动态注入example_group块(和类似的块),从而使它们与我的测试一起运行:

示例

# 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

现在,如果我们假设测试已经打印了一些日志beforeafter,并且在test本身内部,则输出如下所示:

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

由于我们现在正在将before钩子动态注入到与测试相同的上下文中,因此我们不再看到以下错误:

  

before在示例内(例如it块)或在示例范围内运行的构造(例如beforelet,等等)。它仅在示例组(例如describecontext块)上可用

更深入

提供给ex钩子的around参数是RSpec::Core::Example::Procsy的一个实例,它通过RSpec::Core::Example属性提供对example实例的访问。 / p>

RSpec::Core::Example使我们可以通过example_group方法访问与此测试关联的RSpec::Core::ExampleGroup

RSpec::Core::ExampleGroup使我们能够访问DSL /方法,从而使我们能够动态定义before / after / let / etc块,而不会触发not available from within an example错误;如我们在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