Kev*_*ert 1 ruby testing rspec
我正在使用Rspec为我的程序进行一些测试.在一个规范中,我实例化了一次类,并使用describe和contexts对它进行测试.如果它似乎在上下文结束时被评估,我遇到了一些有趣的东西.例如,给定以下类及其相关规范:
class Tmp
def initialize
@values = {}
end
def modify(new_value1, new_value2)
@values = {:a => new_value1, :b => new_value2}
end
def get_values
return @values
end
end
Run Code Online (Sandbox Code Playgroud)
describe Tmp do
tmp = Tmp.new()
describe "testing something" do
context "change value" do
# First evaluation
tmp.modify("hi", "bye")
it {tmp.get_values.should == {:a => "hi", :b => "bye"}}
# Second evaluation
tmp.modify("bye", "hi")
it {tmp.get_values.should == {:a => "bye", :b => "hi"}}
end
end
end
Run Code Online (Sandbox Code Playgroud)
使用提供的类和规范结果如下:
F.
Failures:
1) Tmp testing something change value
Failure/Error: it {tmp.get_values.should == {:a => "hi", :b => "bye"}}
expected: {:a=>"hi", :b=>"bye"}
got: {:a=>"bye", :b=>"hi"} (using ==)
Diff:
@@ -1,3 +1,3 @@
-:a => "hi",
-:b => "bye"
+:a => "bye",
+:b => "hi"
# ./spec/tmp_spec.rb:11:in `block (4 levels) in <top (required)>'
Finished in 0.00211 seconds
2 examples, 1 failure
Run Code Online (Sandbox Code Playgroud)
这很有趣,因为Rspec似乎用tmp中的值来评估第一个,因为它位于上下文的末尾.即使在上下文中tmp正在改变其值并且应该通过,Rspec 也会根据变量在结尾处的最后值来评估它(我甚至尝试使用上下文中的本地原始变量并具有类似的经验).
有没有办法来解决这个问题,并有它的评估,以?或者至少要通过以下测试?我知道我可以使用不同的变量,它会起作用,但必须有办法解决这个问题.我也想知道这是否是对Rspec的预期效果.
关于菲利普答案的更新
通过在单个内部进行更改,阻止规范通过:
describe Tmp do
describe "do something" do
let(:instance) {Tmp.new}
it 'should be modifiable' do
instance.modify('hi', 'bye')
instance.values.should == {a: 'hi', b: 'bye'}
instance.modify('bye', 'hi')
instance.values.should == {a: 'bye', b: 'hi'}
end
end
end
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用这个主题它似乎还原,并在第一个应该失败
describe Tmp do
describe "do something" do
let(:instance) {Tmp.new}
subject{instance.values}
it 'should be modifiable' do
instance.modify('hi', 'bye')
should == {a: 'hi', b: 'bye'}
instance.modify('bye', 'hi')
should == {a: 'bye', b: 'hi'}
end
end
end
Run Code Online (Sandbox Code Playgroud)
不知道为什么会这样.至少我看到更改应该在一个块内,以更好地反映我们正在测试的更改.
你不应该创建实例和外部操纵它们it,specify,before,let,和subject块.否则,在测试后不会重置主题和其他变量.
下面我用几种不同的风格重写了你的规范.有关说明,请参阅内联注释.
class Tmp
# Exposes the @values ivar through #values
attr_reader :values
def initialize
@values = {}
end
def modify(new_value1, new_value2)
@values = {a: new_value1, b: new_value2}
end
end
describe Tmp do
#`let` makes the return value of the block available as a variable named `instance` (technically it is a method named instance, but let's call it a variable).
let(:instance) { described_class.new }
# Inside an it block you can access the variables defined through let.
it 'should be modifiable' do
instance.modify('hi', 'bye')
instance.values.should == {a: 'hi', b: 'bye'}
end
# or
# `specify` is like `it` but it takes no argument:
specify do
instance.modify('hi', 'bye')
instance.values.should == {a: 'hi', b: 'bye'}
end
# or
# This is another common way of defining specs, one describe per method.
describe '#modify' do
let(:instance) { described_class.new }
# Here we define the subject which is used implicitly when calling `#should` directly.
subject { instance.values }
before { instance.modify('hi', 'bye') }
it { should == {a: 'hi', b: 'bye' } # Equivalent to calling `subject.should == ...`
end
# or
# When we don't specify a subject, it will be an instance of the top level described object (Tmp).
describe '#modify' do
before { subject.modify('hi', 'bye') }
its(:values) { should == {a: 'hi', b: 'bye' }
end
end
Run Code Online (Sandbox Code Playgroud)