假设我有以下规范:
...
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 中共享一个变量。我会在一个例子中写一个值,然后在另一个例子中读取它。我该怎么做?
答案 0 :(得分:44)
您应该使用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
在此before(:each)
中的所有示例之前执行一次before(:all)
。我建议您更喜欢before(:all)
而不是get_data_from_file
,因为在这种情况下每个示例都会被隔离,这是一个很好的做法。
在极少数情况下,如果您想使用before(:all)
,例如@data
执行时间较长,在这种情况下,您可以牺牲测试隔离来支持速度。但我想知道您,在使用it
时,在一次测试(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]
[]
<强>已更新强>
回答你的问题
it
将输出
before(:all)
因为在第一个it
中你在本地分配实例变量@a,所以它与object_id
块中的@a不同,并且对其他it
块不可见,您可以输出{{1}}来检查它。因此,只有修改才能完成,分配将导致新的对象创建。
因此,如果您多次分配变量,那么最终可能会有一个{{1}}块和多个期望值。 It is acceptable, according to best practices.
答案 1 :(得分:10)
这就是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
...
答案 2 :(得分:0)
我刚遇到同样的问题。我如何解决它是通过使用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
无论如何,祝你好运,如果你有其他解决方案,我们就知道了!