RSpec
RSpec

RSpec

Published
Published May 9, 2019
Author
RSpec is a Behaviour-Driven Development tool for Ruby programmers.
BDD is an approach to software development that combines Test-Driven Development, Domain Driven Design, and Acceptance Test-Driven Planning.
RSpec helps you do the TDD part of that equation, focusing on the documentation and design aspects of TDD.

Basic Structure

"Describe an order." "It sums the prices of its line items."
RSpec.describe Order do it "sums the prices of its items" do order = Order.new order.add_item(price: Money.new(1.11, :USD) ) order.add_item(price: Money.new(2.22, :USD), quality: 2 ) expect(order.total).to eq(Money.new(5.55, :USD)) end end

Nested Groups

 describe or context 都可以
RSpec.describe Order do context "with no items" do it "behaves one way" {} end context "with one item" do it "behaves another way" {} end end

Shared Examples and Contexts

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
Nearly anything that can be declared within an example group can be declared within a shared example group. This includes beforeafter, and around hooks, let declarations, and nested groups/contexts.
You can also use the names shared_context and include_context. These are pretty much the same as shared_examples and include_examples, providing more accurate naming when you share hooks, let declarations, helper methods, etc, but no examples.
 

Subject

Implicitly defined subject

If the first argument to an example group is a class, an instance of that
class is exposed to each example in that example group via the subject method
RSpec.describe Array do it "should be empty when first created" do expect(subject).to be_empty end describe "when first created" do # `subject` in a nested group it "should be empty" { expect(subject).to be_empty } end end
method.

Explicit Subject

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

One-liner syntax

RSpec.describe Array do describe "with 3 items" do subject { [1,2,3] } it { should_not be_empty } it { is_expected.not_to be_empty } end end

Hooks

Use before and after hooks to execute arbitrary code before and/or afterthe body of an example is run:
before(:example) # run before each example before(:context) # run one time only, before all of the examples in a group after(:example) # run after each example after(:context) # run one time only, after all of the examples in a group

Aliases

You can declare example groups using either describe or context. For a top level example group, describe and context are available off of RSpec. For backwards compatibility, they are also available off of the main object and Module unless you disable monkey patching.
You can declare examples within a group using any of itspecify, or example.

Metadata

rspec-core stores a metadata hash with every example and group, which contains their descriptions, the locations at which they were declared, etc, etc. This hash powers many of rspec-core's features, including output formatters (which access descriptions and locations), and filtering before and after hooks.
Although you probably won't ever need this unless you are writing an extension, you can access it from an example like this:
it "does something" do |example| expect(example.metadata[:description]).to eq("does something") end

described_class

When a class is passed to describe, you can access it from an example using the described_class method, which is a wrapper for example.metadata[:described_class].
RSpec.describe Widget do example do expect(described_class).to equal(Widget) end end
This is useful in extensions or shared example groups in which the specific class is unknown. Taking the collections shared example group from above, we can clean it up a bit using 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

Let

Use let to define a memoized helper method. The value will be cached acrossmultiple calls in the same example but not across examples.
Note that let is lazy-evaluated: it is not evaluated until the first timethe method it defines is invoked. You can use let! to force the method'sinvocation before each example.
By default, let is threadsafe, but you can configure it not to be
$count = 0 RSpec.describe "let" do let(:count) { $count += 1 } it "memoizes the value" do expect(count).to eq(1) expect(count).to eq(1) end it "is not cached across examples" do expect(count).to eq(2) end end