RSpec 仅当 运行 顺序正确时测试 运行s
RSpec test runs correctly only when run in sequence
我有一个似乎是我的测试套件特有的问题。
我有一个模块,它在常量中保存一些默认值,如下所示:
module MyModule
DEFAULTS = {
pool: 15
}
def self.options
@options ||= DEFAULTS
end
def self.options=(opts)
@options = opts
end
end
module MyModule
class MyClass
def options
MyModule.options
end
def import_options(opts)
MyModule.options = opts
end
end
end
我允许程序在没有选项的情况下启动,或者用户可以指定选项。如果没有给出选项,我们将使用默认值,但如果给出了选项,我们将使用默认值。示例测试套件如下所示:
RSpec.describe MyModule::MyClass do
context "with deafults" do
let(:my) { MyModule::MyClass.new }
it 'has a pool of 15' do
expect(my.options[:pool]).to eq 15
end
end
context "imported options" do
let(:my) { MyModule::MyClass.new }
it 'has optional pool size' do
my.import_options(pool: 30)
expect(my.options[:pool]).to eq 30
end
end
end
如果这些测试 运行 按顺序进行,很好,一切都通过了。如果它 运行s 反向(第二个测试先进行),第一个测试的池大小为 30。
我没有 'real world' 会发生这种情况的场景,程序启动一次,仅此而已,但我想相应地对此进行测试。有什么想法吗?
@options
是该模块中的一个 class 变量。我不确定这在技术上是否是正确的名称,但这就是它的行为方式。作为实验,在 self.options
中访问它之前打印出 @options.object_id
。然后 运行 你的测试。您会看到,在这两种情况下,它都打印出相同的 ID。这就是为什么当你的测试被翻转时你得到 30。@options
已经定义所以 @options ||= DEFAULTS
没有将 @options
设置为 DEFAULTS
。
$ cat foo.rb
module MyModule
DEFAULTS = {
pool: 15
}
def self.options
puts "options_id: #{@options.object_id}"
@options ||= DEFAULTS
end
def self.options=(opts)
@options = opts
end
end
module MyModule
class MyClass
def options
MyModule.options
end
def import_options(opts)
MyModule.options = opts
end
end
end
puts "pool 30"
my = MyModule::MyClass.new
my.import_options(pool: 30)
my.options[:pool]
puts
puts "defaults"
my = MyModule::MyClass.new
my.options[:pool]
然后 运行宁...
$ ruby foo.rb
pool 30
options_id: 70260665635400
defaults
options_id: 70260665635400
你总是可以使用 before(:each)
before(:each) do
MyModule.options = MyModule::DEFAULTS
end
旁注 - 可能是配置的 class。
类似于:
module MyModule
class Configuration
def initialize
@foo = 'default'
@bar = 'default'
@baz = 'default'
end
def load_from_yaml(path)
# :)
end
attr_accessor :foo, :bar, :baz
end
end
然后您可以添加如下内容:
module MyModule
class << self
attr_accessor :configuration
end
# MyModule.configure do |config|
# config.baz = 123
# end
def self.configure
self.configuration ||= Configuration.new
yield(configuration)
end
end
最后您将以更有意义的方式重置配置
before(:each) do
MyModule.configuration = MyModule::Configuration.new
end
我有一个似乎是我的测试套件特有的问题。
我有一个模块,它在常量中保存一些默认值,如下所示:
module MyModule
DEFAULTS = {
pool: 15
}
def self.options
@options ||= DEFAULTS
end
def self.options=(opts)
@options = opts
end
end
module MyModule
class MyClass
def options
MyModule.options
end
def import_options(opts)
MyModule.options = opts
end
end
end
我允许程序在没有选项的情况下启动,或者用户可以指定选项。如果没有给出选项,我们将使用默认值,但如果给出了选项,我们将使用默认值。示例测试套件如下所示:
RSpec.describe MyModule::MyClass do
context "with deafults" do
let(:my) { MyModule::MyClass.new }
it 'has a pool of 15' do
expect(my.options[:pool]).to eq 15
end
end
context "imported options" do
let(:my) { MyModule::MyClass.new }
it 'has optional pool size' do
my.import_options(pool: 30)
expect(my.options[:pool]).to eq 30
end
end
end
如果这些测试 运行 按顺序进行,很好,一切都通过了。如果它 运行s 反向(第二个测试先进行),第一个测试的池大小为 30。
我没有 'real world' 会发生这种情况的场景,程序启动一次,仅此而已,但我想相应地对此进行测试。有什么想法吗?
@options
是该模块中的一个 class 变量。我不确定这在技术上是否是正确的名称,但这就是它的行为方式。作为实验,在 self.options
中访问它之前打印出 @options.object_id
。然后 运行 你的测试。您会看到,在这两种情况下,它都打印出相同的 ID。这就是为什么当你的测试被翻转时你得到 30。@options
已经定义所以 @options ||= DEFAULTS
没有将 @options
设置为 DEFAULTS
。
$ cat foo.rb
module MyModule
DEFAULTS = {
pool: 15
}
def self.options
puts "options_id: #{@options.object_id}"
@options ||= DEFAULTS
end
def self.options=(opts)
@options = opts
end
end
module MyModule
class MyClass
def options
MyModule.options
end
def import_options(opts)
MyModule.options = opts
end
end
end
puts "pool 30"
my = MyModule::MyClass.new
my.import_options(pool: 30)
my.options[:pool]
puts
puts "defaults"
my = MyModule::MyClass.new
my.options[:pool]
然后 运行宁...
$ ruby foo.rb
pool 30
options_id: 70260665635400
defaults
options_id: 70260665635400
你总是可以使用 before(:each)
before(:each) do
MyModule.options = MyModule::DEFAULTS
end
旁注 - 可能是配置的 class。
类似于:
module MyModule
class Configuration
def initialize
@foo = 'default'
@bar = 'default'
@baz = 'default'
end
def load_from_yaml(path)
# :)
end
attr_accessor :foo, :bar, :baz
end
end
然后您可以添加如下内容:
module MyModule
class << self
attr_accessor :configuration
end
# MyModule.configure do |config|
# config.baz = 123
# end
def self.configure
self.configuration ||= Configuration.new
yield(configuration)
end
end
最后您将以更有意义的方式重置配置
before(:each) do
MyModule.configuration = MyModule::Configuration.new
end