Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

README improvements #1898

Merged
merged 10 commits into from
Mar 8, 2015
155 changes: 136 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ rspec-core provides the structure for writing executable examples of how your
code should behave, and an `rspec` command with tools to constrain which
examples get run and tailor the output.

## install
## Install

gem install rspec # for rspec-core, rspec-expectations, rspec-mocks
gem install rspec-core # for rspec-core only
Expand All @@ -14,12 +14,12 @@ Want to run against the `master` branch? You'll need to include the dependent
RSpec repos as well. Add the following to your `Gemfile`:

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

## basic structure
## Basic Structure

RSpec uses the words "describe" and "it" so we can express concepts like a conversation:

Expand All @@ -30,13 +30,15 @@ RSpec uses the words "describe" and "it" so we can express concepts like a conve
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
Expand All @@ -49,7 +51,7 @@ Under the hood, an example group is a class in which the block passed to
`describe` is evaluated. The blocks passed to `it` are evaluated in the
context of an _instance_ of that class.

## nested groups
## Nested Groups

You can also declare nested nested groups using the `describe` or `context`
methods:
Expand All @@ -70,7 +72,10 @@ RSpec.describe Order do
end
```

## aliases
Nested groups are subclasses of the outer example group class, providing
the inheritance semantics you'd want for free.

## Aliases

You can declare example groups using either `describe` or `context`.
For a top level example group, `describe` and `context` are available
Expand All @@ -81,7 +86,7 @@ patching.
You can declare examples within a group using any of `it`, `specify`, or
`example`.

## shared examples and contexts
## Shared Examples and Contexts

Declare a shared example group using `shared_examples`, and then include it
in any group using `include_examples`.
Expand Down Expand Up @@ -111,7 +116,7 @@ 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.

## metadata
## Metadata

rspec-core stores a metadata hash with every example and group, which
contains their descriptions, the locations at which they were
Expand Down Expand Up @@ -162,26 +167,106 @@ RSpec.describe Hash do
end
```

## the `rspec` command
## A Word on Scope

RSpec has two scopes:

* **Example Group**: Example groups are defined by a `describe` or
`context` block, which is eagerly evaluated when the spec file is
loaded. The block is evaluated in the context of a subclass of
`RSpec::Core::ExampleGroup`, or a subclass of the parent example group
when you're nesting them.
* **Example**: Examples -- typically defined by an `it` block -- and any other
blocks with per-example semantics -- such as a `before(:example)` hook -- are
evaluated in the context of
an _instance_ of the example group class to which the example belongs.
Examples are _not_ executed when the spec file is loaded; instead,
RSpec waits to run any examples until all spec files have been loaded,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops ;)

at which point it can apply filtering, randomization, etc.

To make this more concrete, consider this code snippet:

``` ruby
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
```

Under the covers, this is (roughly) equivalent to:

``` ruby
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
```

To run these examples, RSpec would (roughly) do the following:

``` ruby
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
```

## The `rspec` Command

When you install the rspec-core gem, it installs the `rspec` executable,
which you'll use to run rspec. The `rspec` command comes with many useful
options.
Run `rspec --help` to see the complete list.

## store command line options `.rspec`
## Store Command Line Options `.rspec`

You can store command line options in a `.rspec` file in the project's root
directory, and the `rspec` command will read them as though you typed them on
the command line.

## autotest integration

rspec-core no longer ships with an Autotest extension, if you require Autotest
integration, please use the `rspec-autotest` gem and see [rspec/rspec-autotest](https://github.com/rspec/rspec-autotest)
for details

## get started
## Get Started

Start with a simple example of behavior you expect from your system. Do
this before you write any implementation code:
Expand All @@ -204,13 +289,12 @@ $ rspec spec/calculator_spec.rb
./spec/calculator_spec.rb:1: uninitialized constant Calculator
```

Implement the simplest solution:
Address the failure by defining a skeleton of the `Calculator` class:

```ruby
# in lib/calculator.rb
class Calculator
def add(a,b)
a + b
def add(a, b)
end
end
```
Expand All @@ -223,6 +307,39 @@ Be sure to require the implementation file in the spec:
require "calculator"
```

Now run the spec again, and watch the expectation fail:

```
$ 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/calcalator_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/calcalator_spec.rb:5 # Calculator#add returns the sum of its arguments
```

Implement the simplest solution, by changing the definition of `Calculator#add` to:

```ruby
def add(a, b)
a + b
end
```

Now run the spec again, and watch it pass:

```
Expand Down