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
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
提供されたクラスと仕様を使用すると、結果は次のようになります。
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
Rspec は、コンテキストの最後にあるtmpの値を使用して最初のitを評価するように見えるため、これは興味深いことです。コンテキスト内でtmpがその値を変更しており、パスする必要がありますが、Rspec は変数が最後に持つ最後の値に基づいてその値を評価します (コンテキスト内のローカル プリミティブ変数でこれを試してみたところ、同様の経験があります)。
これを回避し、順番に評価する方法はありますか? または、少なくとも次のテストに合格するには?さまざまな変数を使用でき、それが機能することはわかっていますが、これを回避する方法が必要です。また、これが Rspec の意図した効果であるかどうかも知りたいです。
フィリップの答えに関する更新
単一のitブロック内で変更を行うことにより、仕様は次のようにパスします。
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
しかし、件名を使用すると、元に戻って最初に失敗するようです
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
なぜそうなのかはわかりません。少なくとも、テスト対象の変更をより適切に反映するために、変更はitブロック内にある必要があることがわかります。