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

rspec-core

rspec-coreは、コードの振る舞いを実行可能な例として記述するための構造を提供し、実行する例を制約し、出力を調整するためのrspecコマンドを提供します。

インストール

gem install rspec # rspec-core、rspec-expectations、rspec-mocks用 gem install rspec-core # rspec-coreのみ用 rspec --help

mainブランチに対して実行したいですか?依存するRSpecリポジトリも含める必要があります。以下をGemfileに追加してください:

%w[rspec rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
end

基本的な構造

RSpecでは、「describe」と「it」という単語を使用して、会話のような概念を表現することができます:

"注文を説明する。" "ラインアイテムの価格を合計する。"

RSpec.describe Order do
it "sums the prices of its line items" do
order = Order.new

order.add_entry(LineItem.new(:item => Item.new(
:price => Money.new(1.11, :USD)
)))
order.add_entry(LineItem.new(:item => Item.new(
:price => Money.new(2.22, :USD),
:quantity => 2
)))

expect(order.total).to eq(Money.new(5.55, :USD))
end
end

describeメソッドはExampleGroupを作成します。describeに渡されたブロック内で、itメソッドを使用して例を宣言することができます。

内部では、例のグループはdescribeに渡されたブロックが評価されるクラスです。itに渡されたブロックは、そのクラスの_インスタンス_のコンテキストで評価されます。

ネストされたグループ

describeまたはcontextメソッドを使用して、ネストされたグループを宣言することもできます:

RSpec.describe Order do
context "with no items" do
it "behaves one way" do
# ...
end
end

context "with one item" do
it "behaves another way" do
# ...
end
end
end

ネストされたグループは、外部の例グループクラスのサブクラスであり、自動的に継承のセマンティクスを提供します。

別名

describeまたはcontextを使用して例グループを宣言することができます。トップレベルの例グループでは、RSpecの下にdescribecontextが利用可能です。後方互換性のために、それらはmainオブジェクトとModuleにも利用可能であり、モンキーパッチを無効にしない限り利用できます。

グループ内で例を宣言するには、itspecify、またはexampleのいずれかを使用できます。

共有の例とコンテキスト

shared_examplesを使用して共有の例グループを宣言し、include_examplesを使用して任意のグループに含めることができます。

RSpec.shared_examples "collections" do |collection_class|
it "is empty when first created" do
expect(collection_class.new).to be_empty
end
end

RSpec.describe Array do
include_examples "collections", Array
end

RSpec.describe Hash do
include_examples "collections", Hash
end

ほとんどのものは、例のグループ内で宣言できるものは、共有の例のグループ内でも宣言できます。これには、beforeafteraroundフック、let宣言、およびネストされたグループ/コンテキストも含まれます。

また、shared_examplesinclude_examplesと同様に、shared_contextinclude_contextという名前も使用できます。これらは、フック、let宣言、ヘルパーメソッドなどを共有する場合に、より正確な命名を提供しますが、例は提供しません。

RSpecスイート全体で共有の例またはコンテキストを再利用する場合は、単独の_*.rb_ファイル(例:spec/support/shared_examples/definition.rb)でそれらを定義することができます。ただし、手動でrequireする必要があります(自分でセットアップしない限り、_spec/support/_ディレクトリは自動的にロードされません)。

メタデータ

rspec-coreは、すべての例とグループにメタデータハッシュを格納しています。このハッシュには、例やグループの説明、宣言された場所などが含まれています。このハッシュは、出力フォーマッタ(説明と場所にアクセスする)やフィルタリング前後のフックなど、rspec-coreの多くの機能を提供しています。

拡張機能を作成していない限り、おそらくこれが必要になることはありませんが、例から次のようにアクセスできます。

it "何かを行う" do |example|
expect(example.metadata[:description]).to eq("何かを行う")
end

described_class

describeにクラスが渡されると、described_classメソッドを使用して例からアクセスできます。これは、example.metadata[:described_class]のラッパーです。

RSpec.describe Widget do
example do
expect(described_class).to equal(Widget)
end
end

これは、特定のクラスが不明な拡張機能や共有の例のグループで便利です。上記の共有の例のグループを取り上げると、described_classを使用して少し整理することができます。

RSpec.shared_examples "collections" do
it "is empty when first created" do
expect(described_class.new).to be_empty
end
end

RSpec.describe Array do
include_examples "collections"
end

RSpec.describe Hash do
include_examples "collections"
end

スコープについて

RSpecには2つのスコープがあります。

  • 例のグループ:例のグループは、describeまたはcontextブロックによって定義されます。これは、スペックファイルがロードされるときに即座に評価されます。ブロックは、RSpec::Core::ExampleGroupのサブクラスまたは親の例のグループのサブクラスのコンテキストで評価されます。
  • :例(通常はitブロックで定義される)およびパーエクスペクトセマンティクスを持つ他のブロック(例:before(:example)フック)は、例が属する例のグループクラスのインスタンスのコンテキストで評価されます。例は、スペックファイルがロードされるときに実行されません。代わりに、RSpecはすべてのスペックファイルがロードされるまで例を実行せず、その後にフィルタリング、ランダム化などを適用します。

以下は、コードスニペットの具体例です。

RSpec.describe "Using an array as a stack" do
def build_stack
[]
end

before(:example) do
@stack = build_stack
end

it 'is initially empty' do
expect(@stack).to be_empty
end

context "after an item has been pushed" do
before(:example) do
@stack.push :item
end

it 'allows the pushed item to be popped' do
expect(@stack.pop).to eq(:item)
end
end
end

内部的には、これは(おおよそ)以下と同等です。

class UsingAnArrayAsAStack < RSpec::Core::ExampleGroup
def build_stack
[]
end

def before_example_1
@stack = build_stack
end

def it_is_initially_empty
expect(@stack).to be_empty
end

class AfterAnItemHasBeenPushed < self
def before_example_2
@stack.push :item
end

def it_allows_the_pushed_item_to_be_popped
expect(@stack.pop).to eq(:item)
end
end
end

これらの例を実行するために、RSpecは(おおよそ)以下のようなことを行います。

example_1 = UsingAnArrayAsAStack.new
example_1.before_example_1
example_1.it_is_initially_empty

example_2 = UsingAnArrayAsAStack::AfterAnItemHasBeenPushed.new
example_2.before_example_1
example_2.before_example_2
example_2.it_allows_the_pushed_item_to_be_popped

rspecコマンド

rspec-core gemをインストールすると、rspec実行可能ファイルがインストールされます。これを使用してrspecを実行します。rspecコマンドには多くの便利なオプションが付属しています。 完全なリストを表示するには、rspec --helpを実行してください。

コマンドラインオプションを.rspecファイルに保存

プロジェクトのルートディレクトリに.rspecファイルにコマンドラインオプションを保存することができます。rspecコマンドは、それらをコマンドラインで入力したかのように読み取ります。

はじめに

システムから期待する振る舞いの単純な例から始めましょう。実装コードを書く前に、これを行ってください。

# in spec/calculator_spec.rb
RSpec.describe Calculator do
describe '#add' do
it 'returns the sum of its arguments' do
expect(Calculator.new.add(1, 2)).to eq(3)
end
end
end

このコードをrspecコマンドで実行し、失敗するのを見てください。

$ rspec spec/calculator_spec.rb
./spec/calculator_spec.rb:1: uninitialized constant Calculator

Calculatorクラスのスケルトンを定義することで、失敗に対処します。

# in lib/calculator.rb
class Calculator
def add(a, b)
end
end

スペックで実装ファイルをrequireすることを忘れないでください。

# in spec/calculator_spec.rb
# - RSpec adds ./lib to the $LOAD_PATH
require "calculator"

スペックを再実行し、期待通りに失敗するのを見てください。

$ rspec spec/calculator_spec.rb
F

Failures:

1) Calculator#add returns the sum of its arguments
Failure/Error: expect(Calculator.new.add(1, 2)).to eq(3)

expected: 3
got: nil

(compared using ==)
# ./spec/calculator_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.00131 seconds (files took 0.10968 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/calculator_spec.rb:5 # Calculator#add returns the sum of its arguments

Calculator#addの定義を以下のように変更して、最も単純な解決策を実装します。

def add(a, b)
a + b
end

スペックを再実行し、成功するのを見てください。

$ rspec spec/calculator_spec.rb
.

Finished in 0.000315 seconds
1 example, 0 failures

結果のスペックを表示するために、documentationフォーマッタを使用してください。

$ rspec spec/calculator_spec.rb --format doc
Calculator
#add
returns the sum of its arguments

Finished in 0.000379 seconds
1 example, 0 failures

他にも参照