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

around フック

around フックは、例をブロック引数として受け取り、プロックとして振る舞うように拡張されます。これにより、例の前後に実行されるコードを定義することができます。もちろん、同じことは before フックと after フックでも行うことができますが、しばしばより簡潔になります。

around フックが輝くのは、例をブロック内で実行したい場合です。たとえば、データベースライブラリがブロックを受け取るトランザクションメソッドを提供している場合、around を使用して例の周りでトランザクションをきれいに開始し、終了することができます。

注意: around フックは、before フックや after フックとは異なり、例と状態を共有しません。つまり、around フックと例の間でインスタンス変数を共有することはできません。

注意: モックフレームワークは、例を実行するコンテキスト内で設定および解除されます。around フックでは直接これらと対話することはできません。

注意: around フックは、定義されたコンテキストに関係なく、before フックの前および after フックの後に実行されます。

around() に渡されたブロック内で例を proc として使用する

次の内容で "example_spec.rb" という名前のファイルがあるとします:

class Database
def self.transaction
puts "open transaction"
yield
puts "close transaction"
end
end

RSpec.describe "around filter" do
around(:example) do |example|
Database.transaction(&example)
end

it "gets run in order" do
puts "run the example"
end
end

rspec example_spec.rb を実行すると

出力には次の内容が含まれるはずです:

open transaction
run the example
close transaction

run() を使用して例を呼び出す

次の内容で "example_spec.rb" という名前のファイルがあるとします:

RSpec.describe "around hook" do
around(:example) do |example|
puts "around example before"
example.run
puts "around example after"
end

it "gets run in order" do
puts "in the example"
end
end

rspec example_spec.rb を実行すると

出力には次の内容が含まれるはずです:

around example before
in the example
around example after

例のメタデータにアクセスする

次の内容で "example_spec.rb" という名前のファイルがあるとします:

RSpec.describe "something" do
around(:example) do |example|
puts example.metadata[:foo]
example.run
end

it "does something", :foo => "this should show up in the output" do
end
end

rspec example_spec.rb を実行すると

出力には "this should show up in the output" という内容が含まれるはずです。

例外が発生しても、around フックは実行を続けます

次の内容で "example_spec.rb" という名前のファイルがあるとします:

  RSpec.describe "something" do
around(:example) do |example|
puts "around example setup"
example.run
puts "around example cleanup"
end

it "still executes the entire around hook" do
fail "the example blows up"
end
end

rspec example_spec.rb を実行すると

出力には "1 example, 1 failure" という内容が含まれるはずです。

グローバルな around フックを定義する

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.configure do |c|
c.around(:example) do |example|
puts "around example before"
example.run
puts "around example after"
end
end

RSpec.describe "around filter" do
it "gets run in order" do
puts "in the example"
end
end

rspec example_spec.rb を実行すると、

以下の出力が含まれるはずです。

around example before
in the example
around example after

各例のフックは around フックで囲まれます

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.describe "around filter" do
around(:example) do |example|
puts "around example before"
example.run
puts "around example after"
end

before(:example) do
puts "before example"
end

after(:example) do
puts "after example"
end

it "gets run in order" do
puts "in the example"
end
end

rspec example_spec.rb を実行すると、

以下の出力が含まれるはずです。

around example before
before example
in the example
after example
around example after

コンテキストのフックは around フックで囲まれません

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.describe "around filter" do
around(:example) do |example|
puts "around example before"
example.run
puts "around example after"
end

before(:context) do
puts "before context"
end

after(:context) do
puts "after context"
end

it "gets run in order" do
puts "in the example"
end
end

rspec --format progress example_spec.rb を実行すると、

以下の出力が含まれるはずです。

before context
around example before
in the example
around example after
.after context

around ブロックで実行される例は設定されたコンテキストで実行されます

以下の内容で "example_spec.rb" という名前のファイルを作成します。

module IncludedInConfigureBlock
def included_in_configure_block; true; end
end

RSpec.configure do |c|
c.include IncludedInConfigureBlock
end

RSpec.describe "around filter" do
around(:example) do |example|
example.run
end

it "runs the example in the correct context" do
expect(included_in_configure_block).to be(true)
end
end

rspec example_spec.rb を実行すると、

出力には "1 example, 0 failure" という文言が含まれるはずです。

暗黙的に保留中の例は「まだ実装されていません」として検出されます

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.describe "implicit pending example" do
around(:example) do |example|
example.run
end

it "should be detected as Not yet implemented"
end

rspec example_spec.rb を実行すると、

出力には "1 example, 0 failures, 1 pending" という文言が含まれるはずです。

また、以下の出力も含まれるはずです。

Pending: (Failures listed here are expected and do not affect your suite's status)

1) implicit pending example should be detected as Not yet implemented
# Not yet implemented
# ./example_spec.rb:6

明示的に保留中の例は保留中として検出されます

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.describe "explicit pending example" do
around(:example) do |example|
example.run
end

it "should be detected as pending" do
pending
fail
end
end

rspec example_spec.rb を実行すると、

出力には "1 example, 0 failures, 1 pending" という文言が含まれるはずです。

また、以下の出力も含まれるはずです。

Pending: (Failures listed here are expected and do not affect your suite's status)

1) explicit pending example should be detected as pending
# No reason given

同じスコープ内に複数の around フックがある場合

以下の内容で "example_spec.rb" という名前のファイルを作成します。

RSpec.describe "if there are multiple around hooks in the same scope" do
around(:example) do |example|
puts "first around hook before"
example.run
puts "first around hook after"
end

around(:example) do |example|
puts "second around hook before"
example.run
puts "second around hook after"
end

it "they should all be run" do
puts "in the example"
expect(1).to eq(1)
end
end

rspec example_spec.rb を実行すると、

出力には "1 example, 0 failure" という文言が含まれるはずです。

また、以下の出力も含まれるはずです。

first around hook before
second around hook before
in the example
second around hook after
first around hook after

複数のスコープでのaroundフック

以下の内容で、"example_spec.rb"という名前のファイルがあるとします。

RSpec.describe "if there are around hooks in an outer scope" do
around(:example) do |example|
puts "first outermost around hook before"
example.run
puts "first outermost around hook after"
end

around(:example) do |example|
puts "second outermost around hook before"
example.run
puts "second outermost around hook after"
end

describe "outer scope" do
around(:example) do |example|
puts "first outer around hook before"
example.run
puts "first outer around hook after"
end

around(:example) do |example|
puts "second outer around hook before"
example.run
puts "second outer around hook after"
end

describe "inner scope" do
around(:example) do |example|
puts "first inner around hook before"
example.run
puts "first inner around hook after"
end

around(:example) do |example|
puts "second inner around hook before"
example.run
puts "second inner around hook after"
end

it "they should all be run" do
puts "in the example"
end
end
end
end

rspec example_spec.rbを実行すると、

出力には "1 example, 0 failure" が含まれているはずです。

また、出力には以下の内容も含まれているはずです。

first outermost around hook before
second outermost around hook before
first outer around hook before
second outer around hook before
first inner around hook before
second inner around hook before
in the example
second inner around hook after
first inner around hook after
second outer around hook after
first outer around hook after
second outermost around hook after
first outermost around hook after