Ruby on rails 我应该如何使用RSpec全局地存根一个方法?

Ruby on rails 我应该如何使用RSpec全局地存根一个方法?,ruby-on-rails,ruby-on-rails-3,rspec,mocking,stubbing,Ruby On Rails,Ruby On Rails 3,Rspec,Mocking,Stubbing,我正在开发一个Rails应用程序。我正在尝试全局地存根一个方法 我要做的是将其存根在RSpec配置中(:suite)之前的块上,如下所示: RSpec.configure do |config| config.before(:suite) do allow_any_instance_of(MyModel).to receive(:my_method).and_return(false) end end 但是,启动测试失败,出现以下错误: 在'method_missing'中:

我正在开发一个Rails应用程序。我正在尝试全局地存根一个方法

我要做的是将其存根在RSpec配置中(:suite)之前的
块上,如下所示:

RSpec.configure do |config|
  config.before(:suite) do
    allow_any_instance_of(MyModel).to receive(:my_method).and_return(false)
  end
end
但是,启动测试失败,出现以下错误:


在'method_missing'中:未定义的方法'allow_any_instance_of'for#(nomethoderor)

有线索吗?我应该如何使用RSpec全局地存根一个方法


p.

这可能是一个上下文/初始化问题。在(:each)
之前的
config.before中执行此操作可以解决您的问题。

您使用的是什么版本的RSpec?我相信RSPEC2.14中引入了
allow\u任何
实例。对于早期版本,您可以使用:

MyModel.any_instance.stub(:my_method).and_return(false)

不要在(:suite)
之前的
中存根方法,因为存根在每个示例之后都会被清除,如中所述:

在(:each)
之前使用
,而不是(:all)
不支持(:all)
之前的
中的存根。原因是所有的存根
每个示例之后,mock都会被清除,所以设置的任何存根
在
之前(:all)
将在碰巧运行的第一个示例中起作用 那群人,但不适合其他人

不要在(:all)
之前使用
,而要在(:each)
之前使用

我想这就是为什么
allow\u任何
实例在
before(:suite)
块中不可用,但在
before(:each)
块中可用的原因

如果仍然缺少该方法,可能您将rspec mock配置为仅允许
:should
语法
的任何实例,并为消息期望提供了所有新的
:expect
语法

通过检查
RSpec::Mocks.configuration.syntax
的值,确保启用此语法。它是rspec模拟中可用语法的数组。可用的语法是
:expect
:should

RSpec.configure do |config|
  config.mock_with :rspec do |mocks|
    mocks.syntax = [:expect, :should]
  end
end

一旦配置正确,您应该能够使用
allow\u任何
的实例,我最近遇到一个案例,我需要在(:all)
之前(:context)
块中存根某个内容,并发现这里的解决方案不适用于我的用例

上的RSpec文档表示不支持:

可以在示例组中直接定义前后挂钩 应在或在全局RSpec.configure块中运行

警告:在before(:suite)中不支持设置实例变量

警告:仅在before(:示例)中支持模拟。

注意:example和:context作用域也可用作:each和 :分别是全部。用你喜欢的

问题 我正在制作包含在unix epoch时间戳中的二进制头文件。我想编写RSpec测试来检查输出文件头的正确性,并将其与测试夹具二进制参考文件进行比较。为了创建快速测试,我需要在所有示例组块运行之前写出一次文件。为了对照引用文件检查时间戳,我需要强制
Time.now()
返回一个常量值。这让我走上了尝试存根
时间的道路。现在
返回我的目标值

但是,由于
rspec/mocks
不支持(:all)
之前的
或(:context)
之前的
块中的存根,因此它不起作用。在(:each)
之前写入文件
会导致其他奇怪的问题

幸运的是,我偶然发现了解决方案

解决方案 自2014年1月9日以来()RSpec现在包含了一个解决此问题的方法:

例子
require'spec\u helper'
需要“rspec/mock”
请描述“LZOP::File”do
前(:全部){
@预期的_lzop_magic=[0x89、0x4c、0x5a、0x4f、0x00、0x0d、0x0a、0x1a、0x0a]
@未压缩的\u文件\u data=“Hello World\n”*100
@文件名='lzoptest.lzo'
@test_fixture_path=File.join(File.dirname(uuu File_uuu)、“…”、“fixtures”、@filename+“.3”)
@lzop_test_fixture_file_data=file.open(@test_fixture_path,'rb')。读取
@tmp_filename=File.basename(@filename)
@tmp_file_path=file.join(“”,'tmp',@tmp_filename)
#Stub调用Time.now(),使用我们的伪mtime值,以便针对我们的测试夹具进行mtime\u low测试
#这是创建原始未压缩测试夹具文件时的mtime
@time_now=time.at(0x544abd86)
}
上下文“当给定文件名时,没有选项并写入未压缩的测试数据”
描述“输出二进制文件”是什么
前(:全部){
RSpec::Mocks.with_temporary_scope do
允许(时间)。接收(:now)。和返回(@Time\u now)
#将“时间是:{TIME.now}”
#将“时间是:{TIME.now.to_i}”
my_test_file=LZOP::file.new(@tmp_file_path)
my_test_file.write(@uncompressed_file_data)
@test_file_data=file.open(@tmp_file_path,'rb')。读取
结束
}
它“有正确的魔法位”做什么
expect(@test\u file\u data[0..8]。解包('C*')。到eq@expected\u lzop\u magic
结束
##[…剪断…](此处的其他示例块)
它“在LZO文件头中具有原始文件mtime”do
#将“time_now={@time_now}
如果@test_file_data[17..21]。解包('L>)。首先&LZOP::F_H_FILTER==0
mtime\U low\U start\U字节=25
mtime\u低端\u字节=28
mtime\u高\u开始\u字节=29
mtime\u高端\u字节=32
其他的
mtime\U low\U start\U字节=29
mtime\u低端\u字节=32
mtime\u高\u开始\u字节=33
mtime\u高端\u字节=36
结束
#放入“开始字节:{开始字节}”
#放置“结束字节:{结束字节}”
#将“mtime_low:#{@test_file_data[start_byte..end_byte].unpack('L>).first.to_s(16)}”
#将“test mtime:{@lzop_test_fixture_file_data[start_byte..end_byte]。解包('L>).f
require 'spec_helper'
require 'rspec/mocks'

describe 'LZOP::File' do
  before(:all) {
    @expected_lzop_magic = [ 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a ]
    @uncompressed_file_data = "Hello World\n" * 100
    @filename = 'lzoptest.lzo'
    @test_fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures', @filename + '.3')
    @lzop_test_fixture_file_data = File.open( @test_fixture_path, 'rb').read
    @tmp_filename = File.basename(@filename)
    @tmp_file_path = File.join( '', 'tmp', @tmp_filename)

    # Stub calls to Time.now() with our fake mtime value so the mtime_low test against our test fixture works
    # This is the mtime for when the original uncompressed test fixture file was created
    @time_now = Time.at(0x544abd86)
  }

  context 'when given a filename, no options and writing uncompressed test data' do

    describe 'the output binary file' do
      before(:all) {
        RSpec::Mocks.with_temporary_scope do
          allow(Time).to receive(:now).and_return(@time_now)
          # puts "TIME IS: #{Time.now}"
          # puts "TIME IS: #{Time.now.to_i}"
          my_test_file = LZOP::File.new( @tmp_file_path )
          my_test_file.write( @uncompressed_file_data )
          @test_file_data = File.open( @tmp_file_path, 'rb').read
        end
      }

      it 'has the correct magic bits' do
        expect( @test_file_data[0..8].unpack('C*') ).to eq @expected_lzop_magic
      end

      ## [...SNIP...] (Other example blocks here)
      it 'has the original file mtime in LZO file header' do
        # puts "time_now= #{@time_now}"

        if @test_file_data[17..21].unpack('L>').first & LZOP::F_H_FILTER == 0
          mtime_low_start_byte=25
          mtime_low_end_byte=28
          mtime_high_start_byte=29
          mtime_high_end_byte=32
        else
          mtime_low_start_byte=29
          mtime_low_end_byte=32
          mtime_high_start_byte=33
          mtime_high_end_byte=36
        end
        # puts "start_byte: #{start_byte}"
        # puts "end_byte: #{end_byte}"
        # puts "mtime_low: #{@test_file_data[start_byte..end_byte].unpack('L>').first.to_s(16)}"
        # puts "test mtime: #{@lzop_test_fixture_file_data[start_byte..end_byte].unpack('L>').first.to_s(16)}"

        mtime_low = @test_file_data[mtime_low_start_byte..mtime_low_end_byte].unpack('L>').first
        mtime_high = @test_file_data[mtime_high_start_byte..mtime_high_end_byte].unpack('L>').first
        # The testing timestamp has no high bits, so this test should pass:
        expect(mtime_low).to eq @time_now.to_i
        expect(mtime_high).to eq 0

        expect(mtime_low).to eq @lzop_test_fixture_file_data[mtime_low_start_byte..mtime_low_end_byte].unpack('L>').first
        expect(mtime_high).to eq @lzop_test_fixture_file_data[mtime_high_start_byte..mtime_high_end_byte].unpack('L>').first

        mtime_fixed = ( mtime_high << 16 << 16 ) | mtime_low

        # puts "mtime_fixed: #{mtime_fixed}"
        # puts "mtime_fixed: #{mtime_fixed.to_s(16)}"

        expect(mtime_fixed).to eq @time_now.to_i

      end
    end
  end
end
class MyModel
  def my_method
    false
  end
end
allow_any_instance_of(Xyz).to receive(:do_this).and_return(:this_is_your_stubbed_output)