Проблема с переменной экземпляра и Rspec 2.x

#rspec

#rspec

Вопрос:

Я использую Rspec 2.0. Я не понимаю, как здесь работает область видимости… Каким-то образом вы можете прочитать переменную в любом блоке, но я не могу ее обновить? почему это?

 describe 'Test App' do
  before(:all) do
    @test= :blah
  end

  it 'test' do
    @test=:bye
    p @test  #  =>  prints bye 
  end

  it 'test' do
    p @test  #  =>  prints blah rather than bye...
  end
end
  

Комментарии:

1. Сегодня вечером нашел эту статью, в которой рассматриваются особенности того, как экземпляр, класс и глобальные переменные отслеживаются в наших тестах. brentlavelle.wordpress.com/2011/04/04 /…

Ответ №1:

Согласно книге RSpec, before(:all) :

… запускается один и только один раз в своем собственном экземпляре Object, но переменные его экземпляра копируются в каждый экземпляр, в котором выполняются примеры. Предостережение при использовании этого: в общем, мы хотим, чтобы каждый пример выполнялся в полной изоляции друг от друга. Как только мы начинаем делиться состоянием между примерами, начинают происходить неожиданные вещи.

Таким образом, в ваших примерах @blah копируется перед запуском каждого теста, поэтому присвоенные ему значения не переносятся из одного примера в другой.

Похоже, вы хотите сделать что-то вроде этого (воздушный код):

 it "gets a token" do
  @token = OAuth.some_method_that_returns_a_token
end

it "uses that token to access some OAuth feature" do
  result = OAuth.some_feature(@token)
  result.should be_something_something
end
  

Это попахивает проверкой OAuth, а не вашего кода. Вам следует рассмотреть возможность отключения some_feature метода (больше кода air):

 it "responds in some way when I use a valid token" do
  @token = mock('token')
  OAuth.should_receive(:some_feature).with(@token).and_return("success")
  result = my_code_which_uses_ouath(@token)
  result.should == "success"
end
  

Ответ №2:

На самом деле все это свойство ruby, а не сам RSpec. Блок before — это обратный вызов, вызываемый перед выполнением каждого it-блока. Так вот как создается экземпляр вашей переменной blah . Когда в вашем втором тесте вы определили, что это будет bye, это определение переопределяется, когда блок before снова вызывается для следующего теста.

Комментарии:

1. Итак, как вы относитесь к ее повторному использованию? Это before (все), поэтому оно должно быть вызвано только один раз на самом деле в этом описании… не a перед каждым

Ответ №3:

Я столкнулся с той же проблемой и решил ее с помощью хэша, в котором я меняю значения:

 describe "carry over value" do
  let (:global) { Hash.new }

  before :all do
   global[:var1] = "foo"
  end

  it "should be foo" do
    global[:var1].should == "foo"
  end

  it "set to bar" do
    global[:var1] = "bar"
    global[:var1].should == "bar"
  end

  it "should still be bar" do
    global[:var1].should == "bar"
  end
end