显式主题

在组范围内使用`subject` 来显式定义在示例范围内由`subject` 方法返回的值。

请注意,虽然下面的示例演示了如何使用`subject` 辅助方法作为用户面向的概念,但我们建议您将其保留用于支持自定义匹配器和/或扩展库,这些库将其实用隐藏在示例之外。

命名的`subject` 通过为其分配上下文语义名称来改进显式的`subject`。由于命名的`subject` 是显式的`subject`,因此它仍然定义了在示例范围内由`subject` 方法返回的值。但是,它定义了一个具有提供的名称的附加辅助方法。此辅助方法被记忆。该值在同一个示例中的多次调用中被缓存,但在示例之间不会被缓存。

我们建议在示例中使用命名的辅助方法而不是`subject`。

有关声明`subject` 的更多信息,请参阅API 文档

可以在顶层组范围内定义和使用`subject`

给定一个名为“top_level_subject_spec.rb”的文件,其中包含

RSpec.describe Array, "with some elements" do
  subject { [1, 2, 3] }

  it "has the prescribed elements" do
    expect(subject).to eq([1, 2, 3])
  end
end

我运行`rspec top_level_subject_spec.rb`

那么这些示例应该全部通过。

在外部组中定义的`subject` 可用于内部组

给定一个名为“nested_subject_spec.rb”的文件,其中包含

RSpec.describe Array do
  subject { [1, 2, 3] }

  describe "has some elements" do
    it "which are the prescribed elements" do
      expect(subject).to eq([1, 2, 3])
    end
  end
end

我运行`rspec nested_subject_spec.rb`

那么这些示例应该全部通过。

`subject` 在示例中被记忆,但在示例之间不会被记忆

注意: 此场景显示了在`subject` 定义块中执行变异。此行为通常不鼓励,因为它使理解规范变得更加困难。此技术仅用作工具来演示记忆是如何发生的。

给定一个名为“memoized_subject_spec.rb”的文件,其中包含

RSpec.describe Array do
  # This uses a context local variable. As you can see from the
  # specs, it can mutate across examples. Use with caution.
  element_list = [1, 2, 3]

  subject { element_list.pop }

  it "is memoized across calls (i.e. the block is invoked once)" do
    expect {
      3.times { subject }
    }.to change{ element_list }.from([1, 2, 3]).to([1, 2])
    expect(subject).to eq(3)
  end

  it "is not memoized across examples" do
    expect{ subject }.to change{ element_list }.from([1, 2]).to([1])
    expect(subject).to eq(2)
  end
end

我运行`rspec memoized_subject_spec.rb`

那么这些示例应该全部通过。

`subject` 在`before` 钩子中可用

给定一个名为“before_hook_subject_spec.rb”的文件,其中包含

RSpec.describe Array, "with some elements" do
  subject { [] }

  before { subject.push(1, 2, 3) }

  it "has the prescribed elements" do
    expect(subject).to eq([1, 2, 3])
  end
end

我运行`rspec before_hook_subject_spec.rb`

那么这些示例应该全部通过。

辅助方法可以从`subject` 定义块中调用

给定一个名为“helper_subject_spec.rb”的文件,其中包含

RSpec.describe Array, "with some elements" do
  def prepared_array
    [1, 2, 3]
  end

  subject { prepared_array }

  it "has the prescribed elements" do
    expect(subject).to eq([1, 2, 3])
  end
end

我运行`rspec helper_subject_spec.rb`

那么这些示例应该全部通过。

使用`subject!` 邦方法在示例之前调用定义块

给定一个名为“subject_bang_spec.rb”的文件,其中包含

RSpec.describe "eager loading with subject!" do
  subject! { element_list.push(99) }

  let(:element_list) { [1, 2, 3] }

  it "calls the definition block before the example" do
    element_list.push(5)
    expect(element_list).to eq([1, 2, 3, 99, 5])
  end
end

我运行`rspec subject_bang_spec.rb`

那么这些示例应该全部通过。

使用`subject(:name)` 定义一个记忆的辅助方法

注意: 虽然下面的示例中使用了全局变量,但在实际规范中强烈不建议使用这种行为。这里只用它来演示该值将在同一个示例中的多次调用中被缓存,但在示例之间不会被缓存。

给定一个名为“named_subject_spec.rb”的文件,其中包含

$count = 0

RSpec.describe "named subject" do
  subject(:global_count) { $count += 1 }

  it "is memoized across calls (i.e. the block is invoked once)" do
    expect {
      2.times { global_count }
    }.not_to change{ global_count }.from(1)
  end

  it "is not cached across examples" do
    expect(global_count).to eq(2)
  end

  it "is still available using the subject method" do
    expect(subject).to eq(3)
  end

  it "works with the one-liner syntax" do
    is_expected.to eq(4)
  end

  it "the subject and named helpers return the same object" do
    expect(global_count).to be(subject)
  end

  it "is set to the block return value (i.e. the global $count)" do
    expect(global_count).to be($count)
  end
end

我运行`rspec named_subject_spec.rb`

那么这些示例应该全部通过。

使用`subject!(:name)` 定义一个在示例之前调用的名为`name` 的辅助方法

给定一个名为“named_subject_bang_spec.rb”的文件,其中包含

RSpec.describe "eager loading using a named subject!" do
  subject!(:updated_list) { element_list.push(99) }

  let(:element_list) { [1, 2, 3] }

  it "calls the definition block before the example" do
    element_list.push(5)
    expect(element_list).to eq([1, 2, 3, 99, 5])
    expect(updated_list).to be(element_list)
  end
end

我运行`rspec named_subject_bang_spec.rb`

那么这些示例应该全部通过。