Rspec it{} 评估使用最后一个变量值 [英] Rspec it{} evaluated uses last variable value

查看:53
本文介绍了Rspec it{} 评估使用最后一个变量值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Rspec 对我的程序进行一些测试.在规范中,我将类实例化一次,然后使用 describescontexts 对其进行测试.我遇到了一些有趣的事情,如果 its 似乎在上下文的末尾被评估.例如,给出以下类及其相关规范:

I'm using Rspec to make some tests for my program. In a spec I instantiate the class once, and perform my tests on it using describes and contexts. I encountered something interesting, if the its seem to be evaluated at the end of the contexts. For example given the following classes and its associated spec:

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

<小时>

使用提供的类和规范,结果如下:


Using the provided class and spec the results are as follows:

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 还是根据变量在结束(我什至在 context 中使用本地原始变量尝试了这个,并且有类似的体验).

This is interesting as Rspec seems to evaluate the first it with the values from tmp as it is at the end of the context. Even though within the context the tmp is changing its values and should pass, Rspec evaluates the its based on the last values that variables have at the ending (I even tried this with a local primitive variable within the context and has a similar experience).

有没有办法解决这个问题并按顺序评估its?或者至少要通过以下测试?我知道我可以使用不同的变量并且它会起作用,但是必须有办法解决这个问题.我也想知道这是否是 Rspec 的预期效果.

Is there a way to get around this and have the its evaluated in order? Or to at least get the following test to pass? I know I can use different variables and it will work, but there must be a way around this. I also want to know if this is an intended effect for Rspec.

关于菲利普的回答的更新

通过在单个 it 块内进行更改,规范通过:

By making the change within a single it block the spec passes:

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

但是如果我使用 subject 它似乎恢复并在第一个 应该

But if I use the subject it seems to revert back and fails on the first should

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 块内,以更好地反映我们正在测试的更改.

Not sure why this is the case. At least I see that the changes should be within a it block to better reflect the changes we're testing for.

推荐答案

你不应该在 itspecify 之外创建和操作它们beforeletsubject 块.否则在测试后不会重置主题和其他变量.

You shouldn't be creating instances and manipulating them outside of it, specify, before, let, and subject blocks. Otherwise the subject and other variables are not reset after a test.

下面我使用几种不同的样式重写了您的规范.请参阅内嵌注释以获取解释.

Below I rewrote your spec using a couple of different styles. See the inline comments for an explanation.

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

这篇关于Rspec it{} 评估使用最后一个变量值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆