Ruby 如何声明RSpec中示例之间共享的变量?
假设我有以下规范:Ruby 如何声明RSpec中示例之间共享的变量?,ruby,variables,rspec,Ruby,Variables,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 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
...
我只想在给定的描述或上下文中共享一个变量。我会在一个例子中写一个值,在另一个例子中读它。如何做到这一点?您应该在(:each)之前或(:all)之前使用
block:
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)
将在本description/context
中的所有示例之前执行一次。我建议您更喜欢(:each)
之前的,而不是(:all)
之前的,因为在这种情况下,每个示例都是孤立的,这是一种很好的做法
很少有情况下,您希望在(:all)
之前使用,例如,如果您的从\u文件中获取\u数据\u的执行时间较长,那么在这种情况下,您当然可以牺牲测试隔离来提高速度。但我想提醒您,当在(:all)
之前使用时,在一个测试(it
块)中修改@data
变量将导致descripe/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
已更新
回答你的问题
describe MyClass do
before(:all) do
@a = []
end
it { @a = [1]; p @a }
it { p @a }
end
将输出
[1]
[]
因为在第一个it
中,您正在本地分配实例变量@a,所以它与之前(:all)
块中的@a不同,并且对其他it
块不可见,所以您可以通过输出对象id
s来检查它。因此,只有修改才能起作用,赋值将导致新对象的创建
所以,如果您多次赋值变量,您可能会得到一个it
块和多个期望值 这正是的目的,它允许您使用代码执行此操作:
...
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
...
我也遇到了同样的问题。我是如何用工厂女孩宝石解决的
以下是基本知识:
创建工厂(以下是代码片段:
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
现在回到您的示例,您可以执行以下操作:
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
无论如何,如果您有其他解决方案,祝您好运!谢谢。我的想法是,我想在一个示例中设置一个变量,并在同一个“描述”或“上下文”块中在另一个示例中读取/更新它。由于某些原因,您提出的解决方案不起作用。@AndreyEsperanza您以前是否尝试过(:all)
?是的。当然,我给出了一个过于简化的示例。现在我正在找出真正的规范可能有什么问题。@AndreyEsperanza我刚刚测试了并在我的答案中添加了相应的示例。也许你应该向我们展示你的代码。你的示例是有效的,但这不是我需要的。这个怎么样:it{@a=[1]};it{p@a}[],而不是[1]
感谢您的回答,但正如您从上面的问题中看到的,我们的想法是在同一个“描述”或“上下文”块中,在一个示例中设置一个变量,并在另一个示例中读取/更新它。