# RSpec Expectations [![Build Status](https://secure.travis-ci.org/rspec/rspec-expectations.svg?branch=master)](http://travis-ci.org/rspec/rspec-expectations) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.svg)](https://codeclimate.com/github/rspec/rspec-expectations) RSpec::Expectations lets you express expected outcomes on an object in an example. expect(account.balance).to eq(Money.new(37.42, :USD)) ## Install If you want to use rspec-expectations with rspec, just install the rspec gem and RubyGems will also install rspec-expectations for you (along with rspec-core and rspec-mocks): gem install rspec 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| gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => 'master' end ``` If you want to use rspec-expectations with another tool, like Test::Unit, Minitest, or Cucumber, you can install it directly: gem install rspec-expectations ## Basic usage Here's an example using rspec-core: ```ruby RSpec.describe Order do it "sums the prices of the items in 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 ``` The `describe` and `it` methods come from rspec-core. The `Order`, `LineItem`, `Item` and `Money` classes would be from _your_ code. The last line of the example expresses an expected outcome. If `order.total == Money.new(5.55, :USD)`, then the example passes. If not, it fails with a message like: expected: # got: # ## Built-in matchers ### Equivalence ```ruby expect(actual).to eq(expected) # passes if actual == expected expect(actual).to eql(expected) # passes if actual.eql?(expected) expect(actual).not_to eql(not_expected) # passes if not(actual.eql?(expected)) ``` Note: The new `expect` syntax no longer supports the `==` matcher. ### Identity ```ruby expect(actual).to be(expected) # passes if actual.equal?(expected) expect(actual).to equal(expected) # passes if actual.equal?(expected) ``` ### Comparisons ```ruby expect(actual).to be > expected expect(actual).to be >= expected expect(actual).to be <= expected expect(actual).to be < expected expect(actual).to be_within(delta).of(expected) ``` ### Regular expressions ```ruby expect(actual).to match(/expression/) ``` Note: The new `expect` syntax no longer supports the `=~` matcher. ### Types/classes ```ruby expect(actual).to be_an_instance_of(expected) # passes if actual.class == expected expect(actual).to be_a(expected) # passes if actual.is_a?(expected) expect(actual).to be_an(expected) # an alias for be_a expect(actual).to be_a_kind_of(expected) # another alias ``` ### Truthiness ```ruby expect(actual).to be_truthy # passes if actual is truthy (not nil or false) expect(actual).to be true # passes if actual == true expect(actual).to be_falsy # passes if actual is falsy (nil or false) expect(actual).to be false # passes if actual == false expect(actual).to be_nil # passes if actual is nil expect(actual).to_not be_nil # passes if actual is not nil ``` ### Expecting errors ```ruby expect { ... }.to raise_error expect { ... }.to raise_error(ErrorClass) expect { ... }.to raise_error("message") expect { ... }.to raise_error(ErrorClass, "message") ``` ### Expecting throws ```ruby expect { ... }.to throw_symbol expect { ... }.to throw_symbol(:symbol) expect { ... }.to throw_symbol(:symbol, 'value') ``` ### Yielding ```ruby expect { |b| 5.tap(&b) }.to yield_control # passes regardless of yielded args expect { |b| yield_if_true(true, &b) }.to yield_with_no_args # passes only if no args are yielded expect { |b| 5.tap(&b) }.to yield_with_args(5) expect { |b| 5.tap(&b) }.to yield_with_args(Fixnum) expect { |b| "a string".tap(&b) }.to yield_with_args(/str/) expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) ``` ### Predicate matchers ```ruby expect(actual).to be_xxx # passes if actual.xxx? expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg) ``` ### Ranges (Ruby >= 1.9 only) ```ruby expect(1..10).to cover(3) ``` ### Collection membership ```ruby expect(actual).to include(expected) expect(actual).to start_with(expected) expect(actual).to end_with(expected) expect(actual).to contain_exactly(individual, items) # ...which is the same as: expect(actual).to match_array(expected_array) ``` #### Examples ```ruby expect([1, 2, 3]).to include(1) expect([1, 2, 3]).to include(1, 2) expect([1, 2, 3]).to start_with(1) expect([1, 2, 3]).to start_with(1, 2) expect([1, 2, 3]).to end_with(3) expect([1, 2, 3]).to end_with(2, 3) expect({:a => 'b'}).to include(:a => 'b') expect("this string").to include("is str") expect("this string").to start_with("this") expect("this string").to end_with("ring") expect([1, 2, 3]).to contain_exactly(2, 3, 1) expect([1, 2, 3]).to match_array([3, 2, 1]) ``` ## `should` syntax In addition to the `expect` syntax, rspec-expectations continues to support the `should` syntax: ```ruby actual.should eq expected actual.should be > 3 [1, 2, 3].should_not include 4 ``` See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/master/Should.md) ## Compound Matcher Expressions You can also create compound matcher expressions using `and` or `or`: ``` ruby expect(alphabet).to start_with("a").and end_with("z") expect(stoplight.color).to eq("red").or eq("green").or eq("yellow") ``` ## Composing Matchers Many of the built-in matchers are designed to take matchers as arguments, to allow you to flexibly specify only the essential aspects of an object or data structure. In addition, all of the built-in matchers have one or more aliases that provide better phrasing for when they are used as arguments to another matcher. ### Examples ```ruby expect { k += 1.05 }.to change { k }.by( a_value_within(0.1).of(1.0) ) expect { s = "barn" }.to change { s } .from( a_string_matching(/foo/) ) .to( a_string_matching(/bar/) ) expect(["barn", 2.45]).to contain_exactly( a_value_within(0.1).of(2.5), a_string_starting_with("bar") ) expect(["barn", "food", 2.45]).to end_with( a_string_matching("foo"), a_value > 2 ) expect(["barn", 2.45]).to include( a_string_starting_with("bar") ) expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/)) hash = { :a => { :b => ["foo", 5], :c => { :d => 2.05 } } } expect(hash).to match( :a => { :b => a_collection_containing_exactly( a_string_starting_with("f"), an_instance_of(Fixnum) ), :c => { :d => (a_value < 3) } } ) expect { |probe| [1, 2, 3].each(&probe) }.to yield_successive_args( a_value < 2, 2, a_value > 2 ) ``` ## Usage outside rspec-core You always need to load `rspec/expectations` even if you only want to use one part of the library: ```ruby require 'rspec/expectations' ``` Then simply include `RSpec::Matchers` in any class: ```ruby class MyClass include RSpec::Matchers def do_something(arg) expect(arg).to be > 0 # do other stuff end end ``` ## Also see * [http://github.com/rspec/rspec](http://github.com/rspec/rspec) * [http://github.com/rspec/rspec-core](http://github.com/rspec/rspec-core) * [http://github.com/rspec/rspec-mocks](http://github.com/rspec/rspec-mocks) * [http://github.com/rspec/rspec-collection_matchers](https://github.com/rspec/rspec-collection_matchers)