p.m*_*los 27 rspec ruby-on-rails mocking stubbing ruby-on-rails-3
我正在研究Rails应用程序.我试图在全局范围内存根.
我正在做的是将其存储在RSpec配置中,在before(:suite)块上,如下所示:
RSpec.configure do |config|
config.before(:suite) do
allow_any_instance_of(MyModel).to receive(:my_method).and_return(false)
end
end
Run Code Online (Sandbox Code Playgroud)
但是,启动测试失败,并出现以下错误:
in `method_missing': undefined method `allow_any_instance_of' for #<RSpec::Core::ExampleGroup:0x00000008d6be08> (NoMethodError)
任何线索?我应该如何使用RSpec全局存根方法?
P.
cbl*_*ard 16
不要使用存根方法,before(:suite)因为在每个示例之后清除存根,如rspec-mocks README中所述:
使用
before(:each),而不是before(:all)
before(:all)不支持存根.原因是在每个示例之后都清除了所有存根和模拟,因此任何设置的存根都before(:all)将在第一个在该组中运行的示例中工作,但不适用于任何其他存根.而不是
before(:all),使用before(:each).
我认为这就是为什么allow_any_instance_of不能在before(:suite)块中提供,但可以在before(:each)块中使用.
如果方法仍然缺失,可能您将rspec-mocks配置为仅允许:should语法.allow_any_instance_of在RSpec 2.14中引入:expect了消息期望的所有新语法.
通过检查值来确保启用此语法RSpec::Mocks.configuration.syntax.它是rspec-mocks中可用语法的数组.可用的语法是:expect和:should.
RSpec.configure do |config|
config.mock_with :rspec do |mocks|
mocks.syntax = [:expect, :should]
end
end
Run Code Online (Sandbox Code Playgroud)
配置正确后,您应该可以使用allow_any_instance_of.
我最近碰到了一个案例,我需要在一个before(:all)或一个before(:context)块中存根,并发现这里的解决方案对我的用例不起作用.
在before()和after()钩子上的RSpec文档说它不受支持:
钩子之前和之后可以直接在它们应该运行的示例组中定义,或者在全局RSpec.configure块中定义.
警告:before(:suite)中不支持设置实例变量.
警告:仅在之前支持模拟(例如).
注意::example和:context作用域也可用作:each和:all.使用您喜欢的任何一种.
我正在制作一个用于编写二进制文件格式的宝石,该格式包含在其二进制头文件中的unix epoch时间戳.我想编写RSpec测试来检查输出文件头是否正确,并将其与测试夹具二进制参考文件进行比较.为了创建快速测试,我需要在所有示例组块运行之前将文件写出一次.为了检查参考文件的时间戳,我需要强制Time.now()返回一个常量值.这导致我试图存根Time.now以返回我的目标值.
但是,由于rspec/mocks不支持在一个before(:all)或before(:context)块内的存根,它不起作用.写文件before(:each)引起了其他奇怪的问题.
幸运的是,我偶然发现了具有解决方案的rspec-mocks问题#240!
自2014年1月9日(rspec-mocks PR#519)以来,RSpec现在包含一种方法来解决这个问题:
RSpec::Mocks.with_temporary_scope
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
Run Code Online (Sandbox Code Playgroud)
如果您希望特定方法在整个测试套件中表现出特定的行为,那么甚至没有理由处理RSpec的存根。相反,您可以简单地(重新)定义方法以在测试环境中表现所需的行为:
class MyModel
def my_method
false
end
end
Run Code Online (Sandbox Code Playgroud)
这可能会进入spec/spec_helper.rb或类似的文件。