Ответ 1
Вероятно, это проблема контекста/инициализации. Выполнение этой задачи в config.before(:each)
должно решить вашу проблему.
Я работаю над приложением 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
Однако при запуске теста сбой происходит со следующей ошибкой:
in `method_missing': undefined method `allow_any_instance_of' for #<RSpec::Core::ExampleGroup:0x00000008d6be08> (NoMethodError)
Любая подсказка? Как я должен заглушить метод глобально с помощью RSpec?
Р.
Вероятно, это проблема контекста/инициализации. Выполнение этой задачи в config.before(:each)
должно решить вашу проблему.
Не останавливайте методы в 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
После правильной настройки вы сможете использовать allow_any_instance_of
.
Недавно я столкнулся с ситуацией, когда мне нужно было что-то заглушить в блоке before(:all)
или before(:context)
, и нашел, что решения здесь не работают для моего использования.
RSpec docs на before() и after() hooks говорит, что он не поддерживается:
до и после крючков можно определить непосредственно в группах примеров, которые они должен выполняться или в глобальном блоке RSpec.configure.
ПРЕДУПРЕЖДЕНИЕ: установка переменных экземпляра не поддерживается ранее (: suite).
ПРЕДУПРЕЖДЕНИЕ: Mocks поддерживается только до (: пример).
Примечание. Области: example и: context также доступны как: каждый и: все, соответственно. Используйте то, что вы предпочитаете.
Я делал драгоценный камень для записи двоичного формата файла, который содержался в timestamp unix-эпохи в двоичном заголовке. Я хотел написать тесты RSpec, чтобы проверить правильность результата выходного файла и сравнить его с бинарным файлом ссылки на тест файл. Чтобы создавать быстрые тесты, мне нужно было записать файл один раз до того, как будут запущены все групповые блоки примера. Чтобы проверить метку времени на ссылочном файле, мне нужно было заставить Time.now()
вернуть постоянное значение. Это привело меня к тому, что я попытался заглушить Time.now
, чтобы вернуть целевое значение.
Однако, поскольку rspec/mocks
не поддерживал stubbing в блоке before(:all)
или before(:context)
, он не работал. Написание файла before(:each)
вызвало другие странные проблемы.
К счастью, я наткнулся на номер # 240 rspec-mocks, у которого было решение!
С 9 января 2014 года (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
Если вы хотите, чтобы какой-либо конкретный метод вел себя определенным образом для всего тестового набора, нет никаких оснований даже иметь дело с контурами RSpec. Вместо этого вы можете просто (повторно) определить, как метод будет вести себя так, как вы хотите в тестовой среде:
class MyModel
def my_method
false
end
end
Это может быть в spec/spec_helper.rb
или аналогичном файле.
Какую версию RSpec вы используете? Я считаю, что allow_any_instance_of
был представлен в RSpec 2.14. Для более ранних версий вы можете использовать:
MyModel.any_instance.stub(:my_method).and_return(false)
Вы можете использовать следующее, чтобы заглушить метод 'do_this' класса 'Xyz':
allow_any_instance_of(Xyz).to receive(:do_this).and_return(:this_is_your_stubbed_output)
Это заглушает вывод в - ': this_is_your_stubbed_output' из любой точки, где вызывается эта функция.
Вы можете использовать вышеуказанный фрагмент кода в блоке before (: each), чтобы сделать это применимым для всех ваших примеров спецификаций.