メインコンテンツまでスキップ

明示的な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」と実行すると、

その後、すべての例が合格する必要があります。

subjectbefore フックで利用可能です

次の内容で "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) を使用して、例の前に呼び出されるヘルパーメソッドを定義する

次の内容で "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 を実行するとき

すべての例が合格する必要があります。