如何声明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 ...
我想要的只是在给定的描述或上下文中共享一个变量。 我会在一个例子中写一个值,然后在另一个例子中读取它。 我怎么做?
您应该使用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)
分别执行before(:each)
在此describe/context
所有示例before(:all)
一次。 我建议你before(:each)
before(:all)
更喜欢before(:all)
,因为在这种情况下每个例子都是孤立的,这是一个很好的做法。
在极少数情况下,如果你想使用before(:all)
,例如你的get_data_from_file
执行时间很长,那么你当然可以牺牲测试隔离来支持速度。 但我想知道你,在使用before(:all)
,在一个测试( 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]
更新
回答你的问题
describe MyClass do before(:all) do @a = [] end it { @a = [1]; p @a } it { p @a } end
会输出
[1] []
因为首先你在本地分配实例变量@a,所以它与before(:all)
块中的@a不同,并且对其他块不可见,你可以通过输出object_id
来检查它。 因此,只有修改才能完成,分配将导致新的对象创建。
因此,如果您多次分配变量,您应该最终得到一个阻塞和多个期望。 根据最佳实践,这是可以接受的。
这实际上是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 ...
我刚遇到同样的问题。 我如何解决它是通过使用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
无论如何,祝你好运,如果你有其他解决方案!