Permalink
Browse files

Improved predicate matchers cuke.

- Use implicit subjects and no doc string.  The doc strings were just noise in these contrived examples.
- Added general discussion of predicate matcher rationale and functionality.
- Added scenario demonstrating passing of arguments from matcher to predicate method.
  • Loading branch information...
1 parent 9e954bc commit 1f1146328334979f740c7920fc795e47ddc6baf2 @myronmarston myronmarston committed Oct 3, 2010
Showing with 76 additions and 38 deletions.
  1. +76 −38 features/matchers/predicates.feature
@@ -1,8 +1,39 @@
Feature: predicate matchers
- As an RSpec user
- I want to set expectations based upon the predicate methods of my objects
- So that I don't have to write a custom matcher for such a simple case
+ Ruby objects commonly provide predicate methods:
+
+ * 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:
+
+ 7.zero?.should == true # fails with "expected true, got false (using ==)"
+
+ ...but RSpec provides dynamic predicate matchers that are more readable and
+ provide better failure output.
+
+ For any predicate method, RSpec gives you a corresponding matcher. Simply
+ prefix the method with "be_" and remove the question mark. Examples:
+
+ * 7.should_not be_zero # calls 7.zero?
+ * [].should be_empty # calls [].empty?
+ * x.should 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.
+
+ * hash.should have_key(:foo) # calls hash.has_key?(:foo)
+ * array.should_not have_odd_values # calls array.has_odd_values?
+
+ In either case, RSpec provides nice, clear error messages, such as:
+
+ expected zero? to return true, got false
+
+ Any arguments passed to the matcher will be passed on to the predicate method.
Scenario: should be_zero (based on Fixnum#zero?)
Given a file named "should_be_zero_spec.rb" with:
@@ -12,54 +43,40 @@ Feature: predicate matchers
end
describe 7 do
- it { should be_zero } # deliberately fail
+ it { should be_zero } # deliberate failure
end
"""
- When I run "rspec ./should_be_zero_spec.rb"
+ When I run "rspec should_be_zero_spec.rb"
Then the output should contain "2 examples, 1 failure"
And the output should contain "expected zero? to return true, got false"
Scenario: should_not be_empty (based on Array#empty?)
Given a file named "should_not_be_empty_spec.rb" with:
"""
- describe Array do
- context "with 3 items" do
- it "is not empty" do
- [1, 2, 3].should_not be_empty
- end
- end
-
- context "with no items" do
- it "is empty, but we'll fail this spec anyway" do
- [].should_not be_empty
- end
- end
+ describe [1, 2, 3] do
+ it { should_not be_empty }
+ end
+
+ describe [] do
+ it { should_not be_empty } # deliberate failure
end
"""
- When I run "rspec ./should_not_be_empty_spec.rb"
+ When I run "rspec should_not_be_empty_spec.rb"
Then the output should contain "2 examples, 1 failure"
And the output should contain "expected empty? to return false, got true"
Scenario: should have_key (based on Hash#has_key?)
Given a file named "should_have_key_spec.rb" with:
"""
describe Hash do
- context 'with :foo => 7' do
- it 'reports that it has the key :foo' do
- { :foo => 7 }.should have_key(:foo)
- end
- end
-
- context 'with nothing' do
- it "has no keys, but we'll fail this spec anyway" do
- {}.should have_key(:foo)
- end
- end
+ subject { { :foo => 7 } }
+ it { should have_key(:foo) }
+ it { should have_key(:bar) } # deliberate failure
end
"""
- When I run "rspec ./should_have_key_spec.rb"
+ When I run "rspec should_have_key_spec.rb"
Then the output should contain "2 examples, 1 failure"
- And the output should contain "expected #has_key?(:foo) to return true, got false"
+ And the output should contain "expected #has_key?(:bar) to return true, got false"
Scenario: should_not have_all_string_keys (based on custom #has_all_string_keys? method)
Given a file named "should_not_have_all_string_keys_spec.rb" with:
@@ -72,19 +89,40 @@ Feature: predicate matchers
describe Hash do
context 'with symbol keys' do
- it "does not have all string keys" do
- { :foo => 7, :bar => 5 }.should_not have_all_string_keys
- end
+ subject { { :foo => 7, :bar => 5 } }
+ it { should_not have_all_string_keys }
end
context 'with string keys' do
- it "has all string keys, and we'll fail this spec anyway" do
- { 'foo' => 7, 'bar' => 5 }.should_not have_all_string_keys
- end
+ subject { { 'foo' => 7, 'bar' => 5 } }
+ it { should_not have_all_string_keys } # deliberate failure
end
end
"""
- When I run "rspec ./should_not_have_all_string_keys_spec.rb"
+ 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"
+ Scenario: matcher arguments are passed on to the predicate method
+ Given a file named "predicate_matcher_argument_spec.rb" with:
+ """
+ class Fixnum
+ def multiple_of?(x)
+ (self % x).zero?
+ end
+ end
+
+ describe 12 do
+ it { should be_multiple_of(3) }
+ it { should_not be_multiple_of(7) }
+
+ # deliberate failures
+ it { should_not be_multiple_of(4) }
+ it { should be_multiple_of(5) }
+ end
+ """
+ When I run "rspec predicate_matcher_argument_spec.rb"
+ Then the output should contain "4 examples, 2 failures"
+ And the output should contain "expected multiple_of?(4) to return false, got true"
+ And the output should contain "expected multiple_of?(5) to return true, got false"
+

0 comments on commit 1f11463

Please sign in to comment.