Permalink
Browse files

Improve the failure messages for the have/has predicate matcher.

- For a case like `foo.should have_some_stuff`, "expected #has_some_stuff? to..." is better than "expected #has_some_stuff?(nil) to...".  The nil is confusing since you didn't pass any arguments.
- For a case like `foo.should have_each_of(:a, 7, "bar")`, "expected #has_each_of?(:a, 7, "bar")" is better than "expected #has_each_of?(:a)".  It's best to include all the arguments rather than just the first one.
  • Loading branch information...
1 parent 27c1205 commit e92aad9c5b7b25fe214d512e56bde3860b75c53a @myronmarston myronmarston committed Jun 11, 2011
Showing with 46 additions and 8 deletions.
  1. +1 −0 Changelog.md
  2. +1 −1 features/built_in_matchers/predicates.feature
  3. +11 −6 lib/rspec/matchers/has.rb
  4. +33 −1 spec/rspec/matchers/has_spec.rb
View
@@ -4,6 +4,7 @@
* Enhancements
* HaveMatcher converts argument using #to_i (Alex Bepple & Pat Maddox)
+ * Improved failure message for the have_xxx matcher (Myron Marston)
### 2.6.0 / 2011-05-12
@@ -101,7 +101,7 @@ Feature: predicate matchers
"""
When I run `rspec should_not_have_all_string_keys_spec.rb`
Then the output should contain "2 examples, 1 failure"
- And the output should contain "expected #has_all_string_keys?(nil) to return false, got true"
+ And the output should contain "expected #has_all_string_keys? to return false, got true"
Scenario: matcher arguments are passed on to the predicate method
Given a file named "predicate_matcher_argument_spec.rb" with:
View
@@ -10,15 +10,15 @@ def matches?(actual)
end
def failure_message_for_should
- "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return true, got false"
+ "expected ##{predicate(@expected)}#{failure_message_args_description} to return true, got false"
end
def failure_message_for_should_not
- "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return false, got true"
+ "expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true"
end
def description
- [method_description(@expected), args_description(@args)].compact.join(' ')
+ [method_description(@expected), args_description].compact.join(' ')
end
private
@@ -30,9 +30,14 @@ def method_description(method)
method.to_s.gsub('_', ' ')
end
- def args_description(args)
- return nil if args.empty?
- args.map { |arg| arg.inspect }.join(', ')
+ def args_description
+ return nil if @args.empty?
+ @args.map { |arg| arg.inspect }.join(', ')
+ end
+
+ def failure_message_args_description
+ desc = args_description
+ "(#{desc})" if desc
end
end
end
@@ -11,14 +11,30 @@
}.should fail_with("expected #has_key?(:a) to return true, got false")
end
+ it 'does not include any args in the failure message if no args were given to the matcher' do
+ o = Object.new
+ def o.has_some_stuff?; false; end
+ expect {
+ o.should have_some_stuff
+ }.to fail_with("expected #has_some_stuff? to return true, got false")
+ end
+
+ it 'includes multiple args in the failure message if multiple args were given to the matcher' do
+ o = Object.new
+ def o.has_some_stuff?(*_); false; end
+ expect {
+ o.should have_some_stuff(:a, 7, "foo")
+ }.to fail_with('expected #has_some_stuff?(:a, 7, "foo") to return true, got false')
+ end
+
it "fails if #has_sym?(*args) returns nil" do
klass = Class.new do
def has_foo?
end
end
lambda {
klass.new.should have_foo
- }.should fail_with("expected #has_foo?(nil) to return true, got false")
+ }.should fail_with(/expected #has_foo.* to return true, got false/)
end
it "fails if target does not respond to #has_sym?" do
@@ -68,6 +84,22 @@ def o.has_sym?(*args)
end
lambda { o.should_not have_sym(:foo) }.should raise_error("Funky exception")
end
+
+ it 'does not include any args in the failure message if no args were given to the matcher' do
+ o = Object.new
+ def o.has_some_stuff?; true; end
+ expect {
+ o.should_not have_some_stuff
+ }.to fail_with("expected #has_some_stuff? to return false, got true")
+ end
+
+ it 'includes multiple args in the failure message if multiple args were given to the matcher' do
+ o = Object.new
+ def o.has_some_stuff?(*_); true; end
+ expect {
+ o.should_not have_some_stuff(:a, 7, "foo")
+ }.to fail_with('expected #has_some_stuff?(:a, 7, "foo") to return false, got true')
+ end
end
describe "has" do

0 comments on commit e92aad9

Please sign in to comment.