diff --git a/features/README.md b/features/README.md index b25ac00c5..557417219 100644 --- a/features/README.md +++ b/features/README.md @@ -2,40 +2,50 @@ rspec-expectations is used to define expected outcomes. +```ruby RSpec.describe Account do it "has a balance of zero when first created" do expect(Account.new.balance).to eq(Money.new(0)) end end +``` ## Basic structure The basic structure of an rspec expectation is: +```ruby expect(actual).to matcher(expected) expect(actual).not_to matcher(expected) +``` Note: You can also use `expect(..).to_not` instead of `expect(..).not_to`. One is an alias to the other, so you can use whichever reads better to you. #### Examples +```ruby expect(5).to eq(5) expect(5).not_to eq(4) +``` ## What is a matcher? A matcher is any object that responds to the following methods: +```ruby matches?(actual) failure_message +``` These methods are also part of the matcher protocol, but are optional: +```ruby does_not_match?(actual) failure_message_when_negated description supports_block_expectations? +``` RSpec ships with a number of built-in matchers and a DSL for writing custom matchers. diff --git a/features/built_in_matchers/README.md b/features/built_in_matchers/README.md index f25bb3646..686620384 100644 --- a/features/built_in_matchers/README.md +++ b/features/built_in_matchers/README.md @@ -7,27 +7,36 @@ respectively on an object. Most matchers can also be accessed using the `(...).s e.g. +```ruby expect(result).to eq(3) expect(list).not_to be_empty pi.should be > 3 +``` ## Object identity +```ruby expect(actual).to be(expected) # passes if actual.equal?(expected) +``` ## Object equivalence +```ruby expect(actual).to eq(expected) # passes if actual == expected +``` ## Optional APIs for identity/equivalence +```ruby expect(actual).to eql(expected) # passes if actual.eql?(expected) expect(actual).to equal(expected) # passes if actual.equal?(expected) # NOTE: `expect` does not support `==` matcher. +``` ## Comparisons +```ruby expect(actual).to be > expected expect(actual).to be >= expected expect(actual).to be <= expected @@ -40,15 +49,19 @@ e.g. expect(actual).to end_with expected # NOTE: `expect` does not support `=~` matcher. +``` ## Types/classes/response +```ruby expect(actual).to be_instance_of(expected) expect(actual).to be_kind_of(expected) expect(actual).to respond_to(expected) +``` ## Truthiness and existentialism +```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_falsey # passes if actual is falsy (nil or false) @@ -56,84 +69,111 @@ e.g. expect(actual).to be_nil # passes if actual is nil expect(actual).to exist # passes if actual.exist? and/or actual.exists? are truthy expect(actual).to exist(*args) # passes if actual.exist?(*args) and/or actual.exists?(*args) are truthy +``` ## 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') +``` ## Predicate matchers +```ruby expect(actual).to be_xxx # passes if actual.xxx? expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg) +``` ### Examples +```ruby expect([]).to be_empty expect(:a => 1).to have_key(:a) +``` ## Collection membership +```ruby expect(actual).to include(expected) expect(array).to match_array(expected_array) # ...which is the same as: expect(array).to contain_exactly(individual, elements) +``` ### Examples +```ruby expect([1, 2, 3]).to include(1) expect([1, 2, 3]).to include(1, 2) expect(:a => 'b').to include(:a => 'b') expect("this string").to include("is str") expect([1, 2, 3]).to contain_exactly(2, 1, 3) expect([1, 2, 3]).to match_array([3, 2, 1]) +``` ## Ranges (1.9+ only) +```ruby expect(1..10).to cover(3) +``` ## Change observation +```ruby expect { object.action }.to change(object, :value).from(old).to(new) expect { object.action }.to change(object, :value).by(delta) expect { object.action }.to change(object, :value).by_at_least(minimum_delta) expect { object.action }.to change(object, :value).by_at_most(maximum_delta) +``` ### Examples +```ruby expect { a += 1 }.to change { a }.by(1) expect { a += 3 }.to change { a }.from(2) expect { a += 3 }.to change { a }.by_at_least(2) +``` ## Satisfy +```ruby expect(actual).to satisfy { |value| value == expected } +``` ## Output capture +```ruby expect { actual }.to output("some output").to_stdout expect { actual }.to output("some error").to_stderr +``` ## Block expectation +```ruby expect { |b| object.action(&b) }.to yield_control expect { |b| object.action(&b) }.to yield_with_no_args # only matches no args expect { |b| object.action(&b) }.to yield_with_args # matches any args expect { |b| object.action(&b) }.to yield_successive_args(*args) # matches args against multiple yields +``` ### Examples +```ruby expect { |b| User.transaction(&b) }.to yield_control expect { |b| User.transaction(&b) }.to yield_with_no_args expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5` expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5 expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5 expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) +``` diff --git a/features/built_in_matchers/all.feature b/features/built_in_matchers/all.feature index e7db8cab0..d2a3103ad 100644 --- a/features/built_in_matchers/all.feature +++ b/features/built_in_matchers/all.feature @@ -2,19 +2,19 @@ Feature: `all` matcher Use the `all` matcher to specify that a collection's objects all pass an expected matcher. This works on any enumerable object. - ```ruby + ```ruby expect([1, 3, 5]).to all( be_odd ) expect([1, 3, 5]).to all( be_an(Integer) ) expect([1, 3, 5]).to all( be < 10 ) expect([1, 3, 4]).to all( be_odd ) # fails - ``` + ``` The matcher also supports compound matchers: - ```ruby + ```ruby expect([1, 3, 5]).to all( be_odd.and be < 10 ) expect([1, 4, 21]).to all( be_odd.or be < 10 ) - ``` + ``` If you are looking for "any" member of a collection that passes an expectation, look at the `include`-matcher. diff --git a/features/built_in_matchers/be.feature b/features/built_in_matchers/be.feature index cbe6180b9..ce4ed433b 100644 --- a/features/built_in_matchers/be.feature +++ b/features/built_in_matchers/be.feature @@ -2,12 +2,12 @@ Feature: `be` matchers There are several related "be" matchers: - ```ruby + ```ruby expect(obj).to be_truthy # passes if obj is truthy (not nil or false) expect(obj).to be_falsey # passes if obj is falsy (nil or false) expect(obj).to be_nil # passes if obj is nil expect(obj).to be # passes if obj is truthy (not nil or false) - ``` + ``` Scenario: The `be_truthy` matcher Given a file named "be_truthy_spec.rb" with: diff --git a/features/built_in_matchers/be_within.feature b/features/built_in_matchers/be_within.feature index 050ca1cb4..9620c17d0 100644 --- a/features/built_in_matchers/be_within.feature +++ b/features/built_in_matchers/be_within.feature @@ -13,9 +13,9 @@ Feature: `be_within` matcher Instead, you should use the `be_within` matcher to check that the value is within a delta of your expected value: - ```ruby + ```ruby expect(area_of_circle).to be_within(0.1).of(28.3) - ``` + ``` Note that the difference between the actual and expected values must be smaller than your delta; if it is equal, the matcher will fail. diff --git a/features/built_in_matchers/comparisons.feature b/features/built_in_matchers/comparisons.feature index d617b026a..255a90936 100644 --- a/features/built_in_matchers/comparisons.feature +++ b/features/built_in_matchers/comparisons.feature @@ -3,12 +3,12 @@ Feature: Comparison matchers RSpec provides a number of matchers that are based on Ruby's built-in operators. These can be used for generalized comparison of values. E.g. - ```ruby + ```ruby expect(9).to be > 6 expect(3).to be <= 3 expect(1).to be < 6 expect('a').to be < 'b' - ``` + ``` Scenario: Numeric operator matchers Given a file named "numeric_operator_matchers_spec.rb" with: diff --git a/features/built_in_matchers/contain_exactly.feature b/features/built_in_matchers/contain_exactly.feature index 7462cc1a9..19fcf0374 100644 --- a/features/built_in_matchers/contain_exactly.feature +++ b/features/built_in_matchers/contain_exactly.feature @@ -4,19 +4,19 @@ Feature: `contain_exactly` matcher that disregards differences in the ordering between the actual and expected array. For example: - ```ruby + ```ruby expect([1, 2, 3]).to contain_exactly(2, 3, 1) # pass expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail - ``` + ``` This matcher is also available as `match_array`, which expects the expected array to be given as a single array argument rather than as individual splatted elements. The above could also be written as: - ```ruby + ```ruby expect([1, 2, 3]).to match_array [2, 3, 1] # pass expect([:a, :c, :b]).to match_array [:a, :c] # fail - ``` + ``` Scenario: Array is expected to contain every value Given a file named "contain_exactly_matcher_spec.rb" with: diff --git a/features/built_in_matchers/cover.feature b/features/built_in_matchers/cover.feature index c80e9e6ce..c0cc40496 100644 --- a/features/built_in_matchers/cover.feature +++ b/features/built_in_matchers/cover.feature @@ -5,11 +5,11 @@ Feature: `cover` matcher expected objects. This works on any object that responds to `#cover?` (such as a `Range`): - ```ruby + ```ruby expect(1..10).to cover(5) expect(1..10).to cover(4, 6) expect(1..10).not_to cover(11) - ``` + ``` Scenario: Range usage Given a file named "range_cover_matcher_spec.rb" with: diff --git a/features/built_in_matchers/end_with.feature b/features/built_in_matchers/end_with.feature index 06c888f41..abfc02d3c 100644 --- a/features/built_in_matchers/end_with.feature +++ b/features/built_in_matchers/end_with.feature @@ -3,11 +3,11 @@ Feature: `end_with` matcher Use the `end_with` matcher to specify that a string or array ends with the expected characters or elements. - ```ruby + ```ruby expect("this string").to end_with "string" expect("this string").not_to end_with "stringy" expect([0, 1, 2]).to end_with 1, 2 - ``` + ``` Scenario: String usage Given a file named "example_spec.rb" with: diff --git a/features/built_in_matchers/equality.feature b/features/built_in_matchers/equality.feature index 0befb434c..cd89ac529 100644 --- a/features/built_in_matchers/equality.feature +++ b/features/built_in_matchers/equality.feature @@ -11,18 +11,18 @@ Feature: Equality matchers rspec-expectations ships with matchers that align with each of these methods: - ```ruby + ```ruby expect(a).to equal(b) # passes if a.equal?(b) expect(a).to eql(b) # passes if a.eql?(b) expect(a).to be == b # passes if a == b - ``` + ``` It also ships with two matchers that have more of a DSL feel to them: - ```ruby + ```ruby expect(a).to be(b) # passes if a.equal?(b) expect(a).to eq(b) # passes if a == b - ``` + ``` Scenario: Compare using eq (==) Given a file named "compare_using_eq.rb" with: diff --git a/features/built_in_matchers/exist.feature b/features/built_in_matchers/exist.feature index c966c2f65..e290e7fd6 100644 --- a/features/built_in_matchers/exist.feature +++ b/features/built_in_matchers/exist.feature @@ -2,9 +2,9 @@ Feature: `exist` matcher The `exist` matcher is used to specify that something exists (as indicated by `#exist?` or `#exists?`): - ```ruby + ```ruby expect(obj).to exist # passes if obj.exist? or obj.exists? - ``` + ``` Scenario: Basic usage Given a file named "exist_matcher_spec.rb" with: diff --git a/features/built_in_matchers/have_attributes.feature b/features/built_in_matchers/have_attributes.feature index 542a1b062..cf30b794d 100644 --- a/features/built_in_matchers/have_attributes.feature +++ b/features/built_in_matchers/have_attributes.feature @@ -2,19 +2,19 @@ Feature: `have_attributes` matcher Use the have_attributes matcher to specify that an object's attributes match the expected attributes: - ```ruby + ```ruby Person = Struct.new(:name, :age) person = Person.new("Jim", 32) expect(person).to have_attributes(:name => "Jim", :age => 32) expect(person).to have_attributes(:name => a_string_starting_with("J"), :age => (a_value > 30) ) - ``` + ``` The matcher will fail if actual doesn't respond to any of the expected attributes: - ```ruby + ```ruby expect(person).to have_attributes(:name => "Jim", :color => 'red') - ``` + ``` Scenario: Basic usage Given a file named "basic_have_attributes_matcher_spec.rb" with: diff --git a/features/built_in_matchers/include.feature b/features/built_in_matchers/include.feature index 1b0dd1a1c..3c478df7f 100644 --- a/features/built_in_matchers/include.feature +++ b/features/built_in_matchers/include.feature @@ -2,7 +2,7 @@ Feature: `include` matcher Use the `include` matcher to specify that a collection includes one or more expected objects. It succeeds if any object of the given collection passes the specified matcher. This works on any object that responds to `#include?` (such as a string or array): - ```ruby + ```ruby expect("a string").to include("a") expect("a string").to include(/a|str/).twice expect("a string").to include("str", "g") @@ -15,11 +15,11 @@ Feature: `include` matcher expect([1, 2]).to include(be_odd) expect([1, 2]).to include(be < 10).at_least(2).times expect([1, 2]).not_to include(17) - ``` + ``` The matcher also provides flexible handling for hashes: - ```ruby + ```ruby expect(:a => 1, :b => 2).to include(:a) expect(:a => 1, :b => 2).to include(:a, :b) expect(:a => 1, :b => 2).to include(:a => 1) @@ -29,7 +29,7 @@ Feature: `include` matcher expect(:a => 1, :b => 2).not_to include(:c) expect(:a => 1, :b => 2).not_to include(:a => 2) expect(:a => 1, :b => 2).not_to include(:c => 3) - ``` + ``` Scenario: Array usage Given a file named "array_include_matcher_spec.rb" with: diff --git a/features/built_in_matchers/match.feature b/features/built_in_matchers/match.feature index 9ef554eb4..0cc0756ed 100644 --- a/features/built_in_matchers/match.feature +++ b/features/built_in_matchers/match.feature @@ -3,12 +3,12 @@ Feature: `match` matcher The `match` matcher calls `#match` on the object, passing if `#match` returns a truthy (not `false` or `nil`) value. `Regexp` and `String` both provide a `#match` method. - ```ruby + ```ruby expect("a string").to match(/str/) # passes expect("a string").to match(/foo/) # fails expect(/foo/).to match("food") # passes expect(/foo/).to match("drinks") # fails - ``` + ``` You can also use this matcher to match nested data structures when composing matchers. diff --git a/features/built_in_matchers/predicates.feature b/features/built_in_matchers/predicates.feature index 890f0e42a..2b974d463 100644 --- a/features/built_in_matchers/predicates.feature +++ b/features/built_in_matchers/predicates.feature @@ -2,20 +2,20 @@ Feature: Predicate matchers Ruby objects commonly provide predicate methods: - ```ruby + ```ruby 7.zero? # => false 0.zero? # => true [1].empty? # => false [].empty? # => true { :a => 5 }.has_key?(:b) # => false { :b => 5 }.has_key?(:b) # => true - ``` + ``` You could use a basic equality matcher to set expectations on these: - ```ruby + ```ruby expect(7.zero?).to eq true # fails with "expected true, got false (using ==)" - ``` + ``` ...but RSpec provides dynamic predicate matchers that are more readable and provide better failure output. @@ -23,19 +23,19 @@ Feature: Predicate matchers For any predicate method, RSpec gives you a corresponding matcher. Simply prefix the method with `be_` and remove the question mark. Examples: - ```ruby + ```ruby expect(7).not_to be_zero # calls 7.zero? expect([]).to be_empty # calls [].empty? expect(x).to be_multiple_of(3) # calls x.multiple_of?(3) - ``` + ``` Alternately, for a predicate method that begins with `has_` like `Hash#has_key?`, RSpec allows you to use an alternate form since `be_has_key` makes no sense. - ```ruby + ```ruby expect(hash).to have_key(:foo) # calls hash.has_key?(:foo) expect(array).not_to have_odd_values # calls array.has_odd_values? - ``` + ``` In either case, RSpec provides nice, clear error messages, such as: diff --git a/features/built_in_matchers/raise_error.feature b/features/built_in_matchers/raise_error.feature index d0e65336d..0d4d74dad 100644 --- a/features/built_in_matchers/raise_error.feature +++ b/features/built_in_matchers/raise_error.feature @@ -3,15 +3,15 @@ Feature: `raise_error` matcher Use the `raise_error` matcher to specify that a block of code raises an error. The most basic form passes if any error is thrown: - ```ruby + ```ruby expect { raise StandardError }.to raise_error - ``` + ``` You can use `raise_exception` instead if you prefer that wording: - ```ruby + ```ruby expect { 3 / 0 }.to raise_exception - ``` + ``` `raise_error` and `raise_exception` are functionally interchangeable, so use the one that makes the most sense to you in any given context. @@ -19,7 +19,7 @@ Feature: `raise_error` matcher In addition to the basic form, above, there are a number of ways to specify details of an error/exception: - ```ruby + ```ruby expect { raise "oops" }.to raise_error expect { raise "oops" }.to raise_error(RuntimeError) expect { raise "oops" }.to raise_error("oops") @@ -27,7 +27,7 @@ Feature: `raise_error` matcher expect { raise "oops" }.to raise_error(RuntimeError, "oops") expect { raise "oops" }.to raise_error(RuntimeError, /op/) expect { raise "oops" }.to raise_error(an_instance_of(RuntimeError).and having_attributes(message: "oops")) - ``` + ``` Scenario: Expecting any error Given a file named "example_spec" with: diff --git a/features/built_in_matchers/respond_to.feature b/features/built_in_matchers/respond_to.feature index 3367a4b2e..90484daf5 100644 --- a/features/built_in_matchers/respond_to.feature +++ b/features/built_in_matchers/respond_to.feature @@ -2,35 +2,35 @@ Feature: `respond_to` matcher Use the `respond_to` matcher to specify details of an object's interface. In its most basic form: - ```ruby + ```ruby expect(obj).to respond_to(:foo) # pass if obj.respond_to?(:foo) - ``` + ``` You can specify that an object responds to multiple messages in a single statement with multiple arguments passed to the matcher: - ```ruby + ```ruby expect(obj).to respond_to(:foo, :bar) # passes if obj.respond_to?(:foo) && obj.respond_to?(:bar) - ``` + ``` If the number of arguments accepted by the method is important to you, you can specify that as well: - ```ruby + ```ruby expect(obj).to respond_to(:foo).with(1).argument expect(obj).to respond_to(:bar).with(2).arguments expect(obj).to respond_to(:baz).with(1..2).arguments expect(obj).to respond_to(:xyz).with_unlimited_arguments - ``` + ``` If your Ruby version supports keyword arguments, you can specify a list of keywords accepted by the method. - ```ruby + ```ruby expect(obj).to respond_to(:foo).with_keywords(:ichi, :ni) expect(obj).to respond_to(:bar).with(2).arguments.and_keywords(:san, :yon) expect(obj).to respond_to(:baz).with_arbitrary_keywords - ``` + ``` Note that this matcher relies entirely upon `#respond_to?`. If an object dynamically responds to a message via `#method_missing`, but does not indicate this via `#respond_to?`, then this diff --git a/features/built_in_matchers/satisfy.feature b/features/built_in_matchers/satisfy.feature index d152f3350..b7ccacfb8 100644 --- a/features/built_in_matchers/satisfy.feature +++ b/features/built_in_matchers/satisfy.feature @@ -3,19 +3,19 @@ Feature: `satisfy` matcher The `satisfy` matcher is extremely flexible and can handle almost anything you want to specify. It passes if the block you provide returns true: - ```ruby + ```ruby expect(10).to satisfy { |v| v % 5 == 0 } expect(7).not_to satisfy { |v| v % 5 == 0 } - ``` + ``` The default failure message ("expected [actual] to satisfy block") is not very descriptive or helpful. To add clarification, you can provide your own description as an argument: - ```ruby + ```ruby expect(10).to satisfy("be a multiple of 5") do |v| v % 5 == 0 end - ``` + ``` @skip-when-ripper-unsupported Scenario: Basic usage diff --git a/features/built_in_matchers/start_with.feature b/features/built_in_matchers/start_with.feature index baf09e9c4..86c29ff92 100644 --- a/features/built_in_matchers/start_with.feature +++ b/features/built_in_matchers/start_with.feature @@ -3,11 +3,11 @@ Feature: `start_with` matcher Use the `start_with` matcher to specify that a string or array starts with the expected characters or elements. - ```ruby + ```ruby expect("this string").to start_with("this") expect("this string").not_to start_with("that") expect([0,1,2]).to start_with(0, 1) - ``` + ``` Scenario: With a string Given a file named "example_spec.rb" with: diff --git a/features/built_in_matchers/throw_symbol.feature b/features/built_in_matchers/throw_symbol.feature index e2fd44878..c6671c94e 100644 --- a/features/built_in_matchers/throw_symbol.feature +++ b/features/built_in_matchers/throw_symbol.feature @@ -3,21 +3,21 @@ Feature: `throw_symbol` matcher The `throw_symbol` matcher is used to specify that a block of code throws a symbol. The most basic form passes if any symbol is thrown: - ```ruby + ```ruby expect { throw :foo }.to throw_symbol - ``` + ``` You'll often want to specify that a particular symbol is thrown: - ```ruby + ```ruby expect { throw :foo }.to throw_symbol(:foo) - ``` + ``` If you care about the additional argument given to throw, you can specify that as well: - ```ruby + ```ruby expect { throw :foo, 7 }.to throw_symbol(:foo, 7) - ``` + ``` Scenario: Basic usage Given a file named "throw_symbol_matcher_spec.rb" with: diff --git a/features/built_in_matchers/types.feature b/features/built_in_matchers/types.feature index 54bfcabbe..841945cc5 100644 --- a/features/built_in_matchers/types.feature +++ b/features/built_in_matchers/types.feature @@ -10,12 +10,12 @@ Feature: Type matchers Both of these matchers have aliases: - ```ruby + ```ruby expect(obj).to be_a_kind_of(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_a(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_an(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_an_instance_of(type) # same as expect(obj).to be_instance_of(type) - ``` + ``` Scenario: With `be_(a_)kind_of` matcher Given a file named "be_kind_of_matcher_spec.rb" with: diff --git a/features/custom_matchers/define_matcher.feature b/features/custom_matchers/define_matcher.feature index 6e7c53f40..47d6352fc 100644 --- a/features/custom_matchers/define_matcher.feature +++ b/features/custom_matchers/define_matcher.feature @@ -394,7 +394,7 @@ Feature: Defining a custom matcher You should handle each `StandardError` with care! Do not handle them all in one. - ```ruby + ```ruby match do |actual| begin '[...] Some code' @@ -402,7 +402,7 @@ Feature: Defining a custom matcher false end end - ``` + ``` Given a file named "error_handling_spec.rb" with: """ruby