是否有可能在Rspec中访问周围环境的主题?

时间:2012-05-11 10:52:22

标签: ruby testing rspec

以下代码不起作用,但它最能说明我正在努力实现的目标

context "this context describes the class" do

  subject do
    # described class is actually a module here
    c = Class.new.extend(described_class)
    c.some_method_that_has_been_added_through_extension
    c
  end

  # ... testing the class itself here ...

  context "instances of this class" do

    subject do
      # this doesn't work because it introduces a endless recursion bug
      # which makes perfectly sense
      subject.new
    end

  end

end

我还尝试在我初始化的内部上下文中使用局部变量 与主题,但没有运气。有没有什么方法可以从内部范围内的主题定义中访问外部范围的主题?

3 个答案:

答案 0 :(得分:3)

使用#subject有时会造成麻烦。它主要用于#its等短手检查。

它也可以使示例更难阅读,因为它可以掩盖您测试的名称/意图。以下是David Chelimsky撰写的关于#subject和#let主题的博客文章及其在揭示意图中的作用:http://blog.davidchelimsky.net/blog/2012/05/13/spec-smell-explicit-use-of-subject/

请尝试使用let https://www.relishapp.com/rspec/rspec-core/v/2-10/docs/helper-methods/let-and-let

以下是我最有可能写的内容。

context "this context describes the class" do
  let(:name_of_the_module) { Class.new.extend(described_class) }
  before do
    c.some_method_that_has_been_added_through_extension
  end

  # ... testing the class itself here ...

  context "instances of this class" do

    let(:better_name_that_describes_the_instance) { klass.new }

    # ... test the instance
  end

end

旁注 您可能想要重新审视是否要使用主题。我几乎在所有情况下都喜欢使用#let。 YMMV

答案 1 :(得分:0)

显然有效的方法是在内部上下文中使用实例变量,而不是使用subject而是subject.call初始化它。主题是过程。因此,我的第一种方法不起作用。

context "instances of this class" do

  klass = subject.call
  subject { klass.new }

end

答案 2 :(得分:0)

我一直在寻找解决方案,但出于不同的原因。当我测试一个可能返回值或引发错误的方法时,我经常需要在两个上下文中重复该主题,一次作为raise_error的proc和一次正常。

我发现您可以提供subjects名称,例如lets。这样,您就可以从新subject中的外部作用域引用已命名的subject。这是一个例子:

describe 'do_some_math' do
  let!(:calculator) { create(:calculator) }

  # proc to be used with raise_error
  subject(:do_some_math) { 
    -> { calculator.do_some_math(with, complicated, args) } 
  }

  context 'when something breaks' do
    it { is_expected.to raise_error } # ok
  end

  context 'when everything works' do

    # here we call the named subject from the outer scope:
    subject { do_some_math.call } # nice and DRY

    it { is_expected.to be_a(Numeric) } # also ok!
  end
end