web-dev-qa-db-ja.com

RSpecの例間で共有される変数を宣言する方法は?

次の仕様があると仮定します。

...
describe Thing do

  it 'can read data' do
     @data = get_data_from_file  # [ '42', '36' ]
     expect(@data.count).to eq 2
  end

  it 'can process data' do
     expect(@data[0].to_i).to eq 42  # Fails because @data is nil
  end

end
...

私が望んだのは、与えられたdescribeまたはcontextで変数を共有することです。ある例では値を書き、別の例ではそれを読みます。それ、どうやったら出来るの?

36

before(:each)またはbefore(:all)ブロックを使用する必要があります。

describe Thing do
  before(:each) do
    @data = get_data_from_file  # [ '42', '36' ]
  end

  it 'can read data' do
    expect(@data.count).to eq 2
  end

  it 'can process data' do
    expect(@data[0].to_i).to eq 42
  end
end

違いは、_before(:each)は各ケースに対して個別に実行され、_before(:all)はこのdescribe/contextのすべての例の前に1回実行されることです。 before(:each)よりもbefore(:all)を好むことをお勧めします。この場合、各例は分離されるため、良い習慣です。

get_data_from_fileの実行時間が長い場合など、before(:all)を使用したい場合はまれです。この場合、もちろん速度を優先してテストの分離を犠牲にすることができます。ただし、before(:all)を使用する場合、1つのテスト(itブロック)で@data変数を変更すると、describe/contextスコープ内の他のテストに予期しない結果が生じることに注意してください。それ。

before(:all)の例:

describe MyClass do
  before(:all) do
    @a = []
  end

  it { @a << 1; p @a }
  it { @a << 2; p @a }
  it { @a << 3; p @a }
end

出力されます:

[1]
[1, 2]
[1, 2, 3]

[〜#〜] updated [〜#〜]

あなたの質問に答えるために

describe MyClass do
  before(:all) do
    @a = []
  end

  it { @a = [1]; p @a }
  it { p @a }
end

出力します

[1]
[]

最初のitでは、インスタンス変数@aをローカルに割り当てているため、before(:all)ブロックの@aと同じではなく、他のitブロックからは見えません。 、object_idsを出力することで確認できます。そのため、変更のみがトリックを行い、割り当てにより新しいオブジェクトが作成されます。

したがって、変数を複数回割り当てている場合は、おそらく1つのitブロックとその中に複数の期待値があるはずです。 ベストプラクティスによると、許容範囲内です

45

これは実際に RSpec let helper の目的であり、コードでこれを行うことができます。

...
describe Thing do
  let(:data) { get_data_from_file }

  it 'can read data' do
     expect(data.count).to eq 2
  end

  it 'can process data' do
     expect(data[0].to_i).to eq 42
  end

end
...
11
Anthony

私はちょうどこの同じ問題に出くわしました。 factory_girl gemを使用して解決しました。

基本は次のとおりです。

ファクトリを作成します(コードスニペットは次のとおりです。

require 'factory_girl'
require 'faker' # you can use faker, if you want to use the factory to generate fake data

FactoryGirl.define do
  factory :generate_data, class: MyModule::MyClass do
    key 'value'
  end
end

ファクトリを作成したら、次のようなモデルを作成する必要があります。

Module MyModule
  class MyClass
    attr_accessor :key

    #you can also place methods here to call from your spec test, if you wish
    # def self.test
        #some test
    # end
  end
end

例に戻ると、次のようなことができます。

describe Thing do
  before(:all) do
  @data = FactoryGirl.build(:generate_data)
  end

  it 'can read data' do
     @data.key = get_data_from_file  # [ '42', '36' ]
     expect(@data.key.count).to eq 2
  end

  it 'can process data' do
     expect(@data.key[0].to_i).to eq 42  # @data will not be nil. at this point. whatever @data.key is equal to last which was set in your previous context will be what data.key is here
  end

end

とにかく、他の解決策があれば幸運をお知らせします!

0
adbarads