Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: rspec/rspec-mocks
...
head fork: rspec/rspec-mocks
Checking mergeability… Don't worry, you can still create the pull request.
  • 14 commits
  • 19 files changed
  • 0 commit comments
  • 4 contributors
Commits on Dec 14, 2010
@dchelimsky dchelimsky bump version to 2.4.0.pre 89fc6cb
Commits on Dec 18, 2010
@dchelimsky dchelimsky dev-support: update relish task ec53f43
Commits on Dec 21, 2010
@dchelimsky dchelimsky reorganize the nav for relish 3c9bf80
Commits on Dec 30, 2010
@dchelimsky dchelimsky syntax cheat sheets for stubs and messae expectations c42ea70
Commits on Dec 31, 2010
@dchelimsky dchelimsky fix changelog link 0358d7f
Commits on Jan 02, 2011
@dchelimsky dchelimsky prep for 2.4.0 release 866f34a
Commits on Jan 16, 2011
@dnurzynski dnurzynski Fix bug: Message expectation counts don't work in combination with a …
…stub

- Closes #28.
- Closes #33.
dc1044a
@dchelimsky dchelimsky update history 4e7ea7d
Commits on Jan 17, 2011
@dchelimsky dchelimsky docs 38a6295
Commits on Feb 05, 2011
@txus txus Fix failure message when message received with incorrect args.
- Closes #34.
77844a3
@dchelimsky dchelimsky changelog eaa4468
@Flameeyes Flameeyes Don't force cucumber presence on Rakefile.
Only define the cucumber tasks if cucumber is available, allowing for the
Rakefile to work without Cucumber installed.

Note that Cucumber is still part of the bundle, so unless you're
disabling bundler as well, this patch has no effect.

See #35 for background.

- Closes #35.
24f8354
@dchelimsky dchelimsky doc tweaks f7e2297
@dchelimsky dchelimsky prep for 2.5 release a6c98bd
View
53 Rakefile
@@ -5,15 +5,6 @@ Bundler::GemHelper.install_tasks
require 'rake'
require 'rspec/core/rake_task'
require 'rspec/mocks/version'
-require 'cucumber/rake/task'
-
-class Cucumber::Rake::Task::ForkedCucumberRunner
- # When cucumber shells out, we still need it to run in the context of our
- # bundle.
- def run
- sh "bundle exec #{RUBY} " + args.join(" ")
- end
-end
task :cleanup_rcov_files do
rm_rf 'coverage.data'
@@ -24,8 +15,6 @@ RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = %w[--color]
end
-Cucumber::Rake::Task.new(:cucumber)
-
namespace :spec do
desc "Run all examples using rcov"
RSpec::Core::RakeTask.new :rcov => :cleanup_rcov_files do |t|
@@ -35,17 +24,35 @@ namespace :spec do
end
end
-namespace :cucumber do
- desc "Run cucumber features using rcov"
- Cucumber::Rake::Task.new :rcov => :cleanup_rcov_files do |t|
- t.cucumber_opts = %w{--format progress}
- t.rcov = true
- t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,features"]
- t.rcov_opts << %[--text-report --sort coverage --aggregate coverage.data]
+task :default => :spec
+
+begin
+ require 'cucumber/rake/task'
+
+ class Cucumber::Rake::Task::ForkedCucumberRunner
+ # When cucumber shells out, we still need it to run in the context of our
+ # bundle.
+ def run
+ sh "bundle exec #{RUBY} " + args.join(" ")
+ end
end
-end
-task :default => [:spec, :cucumber]
+ Cucumber::Rake::Task.new(:cucumber)
+
+ namespace :cucumber do
+ desc "Run cucumber features using rcov"
+ Cucumber::Rake::Task.new :rcov => :cleanup_rcov_files do |t|
+ t.cucumber_opts = %w{--format progress}
+ t.rcov = true
+ t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,features"]
+ t.rcov_opts << %[--text-report --sort coverage --aggregate coverage.data]
+ end
+ end
+
+ task :default => :cucumber
+rescue LoadError
+ $stderr.puts "unable to load cucumber, some tasks unavailable"
+end
task :clobber do
rm_rf 'pkg'
@@ -61,10 +68,8 @@ Rake::RDocTask.new do |rdoc|
rdoc.rdoc_files.include('lib/**/*.rb')
end
-desc "Push cukes to relishapp using the relish-client-gem"
+desc "Push docs/cukes to relishapp using the relish-client-gem"
task :relish, :version do |t, args|
raise "rake relish[VERSION]" unless args[:version]
- sh "relish push --organization rspec --project rspec-mocks -v #{args[:version]}"
+ sh "relish push rspec/rspec-mocks:#{args[:version]}"
end
-
-task :default => [:spec, :cucumber]
View
13 features/.nav
@@ -0,0 +1,13 @@
+- Upgrade.md
+- Changelog.md
+- method_stubs:
+ - simple_return_value.feature
+ - stub_implementation.feature
+ - stub_chain.feature
+- message_expectations:
+ - expect_message.feature
+ - block_local_expectations.feature.pending
+ - warn_when_expectation_is_set_on_nil.feature
+- outside_rspec:
+ - configuration.feature
+ - standalone.feature
View
19 History.markdown → features/Changelog.md
@@ -1,8 +1,23 @@
-## rspec-mocks release history (incomplete)
+### 2.5.0 / 2011-02-05
+
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.4.0...v2.5.0)
+
+* Bug fixes
+ * message expectation counts now work in combination with a stub (Damian
+ Nurzynski)
+ * fix failure message when message received with incorrect args (Josep M.
+ Bach)
+
+### 2.4.0 / 2011-01-02
+
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.3.0...v2.4.0)
+
+No functional changes in this release, which was made to align with the
+rspec-core-2.4.0 release.
### 2.3.0 / 2010-12-12
-[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.2.1...v2.3.0)
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.2.0...v2.3.0)
* Bug fixes
* Fix our Marshal extension so that it does not interfere with objects that
View
7 features/README.markdown
@@ -1,6 +1,6 @@
rspec-mocks is used to create dynamic "doubles", which stand in for real
-objects in examples. You can set message expectations on them (i.e. mock
-methods), and/or stub return values for arbitrary messages:
+objects in examples. You can stub return values and/or set message
+expectations:
describe Account do
context "when closed" do
@@ -16,9 +16,6 @@ methods), and/or stub return values for arbitrary messages:
end
end
-Message expectations like the one in the example above are verified at
-the end of each example.
-
## Issues
The documentation for rspec-mocks is a work in progress. We'll be adding
View
0  Upgrade.markdown → features/Upgrade.md
File renamed without changes
View
58 features/message_expectations/README.md
@@ -0,0 +1,58 @@
+### Basics
+
+ # create a double
+ obj = double()
+
+ # expect a message
+ obj.should_receive(:message)
+
+ # specify a return value
+ obj.should_receive(:message) { 'this is the value to return' }
+
+### Argument constraints
+
+#### Explicit arguments
+
+ obj.should_receive(:message).with('an argument')
+ obj.should_receive(:message).with('more_than', 'one_argument')
+
+#### Argument matchers
+
+ obj.should_receive(:message).with(anything())
+ obj.should_receive(:message).with(an_instance_of(Money))
+ obj.should_receive(:message).with(hash_including(:a => 'b'))
+
+#### Regular expressions
+
+ obj.should_receive(:message).with(/abc/)
+
+### Counts
+
+ obj.should_receive(:message).once
+ obj.should_receive(:message).twice
+ obj.should_receive(:message).exactly(3).times
+
+ obj.should_receive(:message).at_least(:once)
+ obj.should_receive(:message).at_least(:twice)
+ obj.should_receive(:message).at_least(n).times
+
+ obj.should_receive(:message).at_most(:once)
+ obj.should_receive(:message).at_most(:twice)
+ obj.should_receive(:message).at_most(n).times
+
+### Raising/Throwing
+
+ obj.should_receive(:message) { raise "this error" }
+ obj.should_receive(:message) { throw :this_symbol }
+
+### Ordering
+
+ obj.should_receive(:one).ordered
+ obj.should_receive(:two).ordered
+
+### Arbitrary handling
+
+ obj.should_receive(:message) do |arg1, arg2|
+ # set expectations about the args in this block
+ # and set a return value
+ end
View
2  features/message_expectations/expect_message.feature
@@ -1,4 +1,4 @@
-Feature: Expect a message
+Feature: expect a message
Use should_receive() to set an expectation that a receiver should receive a
message before the example is completed.
View
2  features/message_expectations/warn_when_expectation_is_set_on_nil.feature
@@ -1,4 +1,4 @@
-Feature: Warn when expectation is set on nil
+Feature: warn when expectation is set on nil
Scenario: nil instance variable
Given a file named "example_spec.rb" with:
View
39 features/method_stubs/README.md
@@ -0,0 +1,39 @@
+### Basics
+
+ # create a double
+ obj = double()
+
+ # stub a method
+ obj.stub(:message) # returns obj
+
+ # specify a return value
+ obj.stub(:message) { 'this is the value to return' }
+
+### Argument constraints
+
+#### Explicit arguments
+
+ obj.stub(:message).with('an argument')
+ obj.stub(:message).with('more_than', 'one_argument')
+
+#### Argument matchers
+
+ obj.stub(:message).with(anything())
+ obj.stub(:message).with(an_instance_of(Money))
+ obj.stub(:message).with(hash_including(:a => 'b'))
+
+#### Regular expressions
+
+ obj.stub(:message).with(/abc/)
+
+### Raising/Throwing
+
+ obj.stub(:message) { raise "this error" }
+ obj.stub(:message) { throw :this_symbol }
+
+### Arbitrary handling
+
+ obj.stub(:message) do |arg1, arg2|
+ # set expectations about the args in this block
+ # and set a return value
+ end
View
4 features/stubs/simple_return_value.feature → features/method_stubs/simple_return_value.feature
@@ -1,6 +1,6 @@
-Feature: Stub with simple return value
+Feature: stub with a simple return value
- Use the stub() method on a test double or a real object to tell the object to
+ Use the `stub` method on a test double or a real object to tell the object to
return a value (or values) in response to a given message. If the message is
never received, nothing happens.
View
16 features/stubs/stub_chain.feature → features/method_stubs/stub_chain.feature
@@ -1,23 +1,23 @@
-Feature: Stub a chain of methods
+Feature: stub a chain of methods
- The stub_chain method lets you to stub a chain of methods in one statement.
+ The `stub_chain` method lets you to stub a chain of methods in one statement.
Method chains are considered a design smell, but it's not really the method
chain that is the problem - it's the dependency chain represented by a chain
of messages to different objects:
- foo.get_bar.get_baz
+ foo.get_bar.get_baz
- This is a Law of Demeter violation if get_bar() returns an object other than
- foo, and get_baz() returns yet another object.
+ This is a Law of Demeter violation if `get_bar` returns an object other than
+ `foo`, and `get_baz` returns yet another object.
Fluent interfaces look similar from a caller's perspective, but don't
represent a dependency chain (the caller depends only on the object it is
calling). Consider this common example from Ruby on Rails:
- Article.recent.by(current_user)
+ Article.recent.by(current_user)
- The recent() and by() methods return the same object, so this is not
- a Law of Demeter violation.
+ The `recent` and `by` methods return the same object, so this is not a Law of
+ Demeter violation.
Scenario: stub a chain of methods
Given a file named "stub_chain_spec.rb" with:
View
2  features/stubs/stub_implementation.feature → features/method_stubs/stub_implementation.feature
@@ -1,4 +1,4 @@
-Feature: Stub with substitute implementation
+Feature: stub with substitute implementation
You can stub an implementation of a method (a.k.a. fake) by passing a block
to the stub() method.
View
2  features/outside_rspec/configuration.feature
@@ -1,4 +1,4 @@
-Feature: Configure any test framework to use rspec-mocks
+Feature: configure any test framework to use rspec-mocks
Test frameworks that want to use rspec-mocks can use
RSpec::Mocks::setup(self) to hook into rspec-mocks. Doing so adds the
View
2  features/outside_rspec/standalone.feature
@@ -4,7 +4,7 @@ Feature: standalone
outside the RSpec environment. This is especially useful for
exploring rspec-mocks in irb.
- Scenario: stub outside rspec
+ Scenario: method stub outside rspec
Given a file named "example.rb" with:
"""
require "rspec/mocks/standalone"
View
16 lib/rspec/mocks/message_expectation.rb
@@ -24,6 +24,7 @@ def initialize(error_generator, expectation_ordering, expected_from, sym, method
@order_group = expectation_ordering
@at_least = nil
@at_most = nil
+ @exactly = nil
@args_to_yield = []
@failed_fast = nil
@args_to_yield_were_cloned = false
@@ -286,13 +287,13 @@ def never
def once(&block)
@method_block = block if block
- @expected_received_count = 1
+ set_expected_received_count :exactly, 1
self
end
def twice(&block)
@method_block = block if block
- @expected_received_count = 2
+ set_expected_received_count :exactly, 2
self
end
@@ -307,10 +308,19 @@ def negative_expectation_for?(sym)
return false
end
+ def actual_received_count_matters?
+ @at_least || @at_most || @exactly
+ end
+
+ def increase_actual_received_count!
+ @actual_received_count += 1
+ end
+
protected
def set_expected_received_count(relativity, n)
@at_least = (relativity == :at_least)
@at_most = (relativity == :at_most)
+ @exactly = (relativity == :exactly)
@expected_received_count = case n
when Numeric
n
@@ -324,7 +334,7 @@ def set_expected_received_count(relativity, n)
def clear_actual_received_count!
@actual_received_count = 0
end
-
+
end
class NegativeMessageExpectation < MessageExpectation
View
3  lib/rspec/mocks/proxy.rb
@@ -96,6 +96,7 @@ def message_received(method_name, *args, &block)
stub = find_matching_method_stub(method_name, *args)
if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
+ expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
if expectation = find_almost_matching_expectation(method_name, *args)
expectation.advise(*args) unless expectation.expected_messages_received?
end
@@ -141,7 +142,7 @@ def find_matching_expectation(method_name, *args)
end
def find_almost_matching_expectation(method_name, *args)
- method_double[method_name].expectations.find {|expectation| expectation.matches_name_but_not_args(method_name, *args)}
+ method_double[method_name].expectations.find {|expectation| expectation.matches_name_but_not_args(method_name, *args) && !expectation.called_max_times?}
end
def find_matching_method_stub(method_name, *args)
View
2  lib/rspec/mocks/version.rb
@@ -1,7 +1,7 @@
module RSpec # :nodoc:
module Mocks # :nodoc:
module Version # :nodoc:
- STRING = '2.3.0'
+ STRING = '2.5.0'
end
end
end
View
11 spec/rspec/mocks/mock_spec.rb
@@ -109,6 +109,17 @@ module Mocks
}.should raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
end
+ describe "even when a similar expectation with different arguments exist" do
+ it "raises exception if args don't match when method called, correctly reporting the offending arguments" do
+ @mock.should_receive(:something).with("a","b","c").once
+ @mock.should_receive(:something).with("z","x","c").once
+ lambda {
+ @mock.something("a","b","c")
+ @mock.something("z","x","g")
+ }.should raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"z\", \"x\", \"c\")\n got: (\"z\", \"x\", \"g\")")
+ end
+ end
+
it "raises exception if args don't match when method called even when the method is stubbed" do
@mock.stub(:something)
@mock.should_receive(:something).with("a","b","c")
View
78 spec/rspec/mocks/multiple_return_value_spec.rb
@@ -8,7 +8,7 @@ module Mocks
@return_values = ["1",2,Object.new]
@mock.should_receive(:message).and_return(@return_values[0],@return_values[1],@return_values[2])
end
-
+
it "returns values in order to consecutive calls" do
@mock.message.should == @return_values[0]
@mock.message.should == @return_values[1]
@@ -20,7 +20,7 @@ module Mocks
@mock.message.should == @return_values[0]
@mock.message.should == @return_values[1]
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 2 times|
)
end
@@ -31,10 +31,19 @@ module Mocks
@mock.message.should == @return_values[2]
@mock.message.should == @return_values[2]
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 4 times|
)
end
+
+ it "doesn't complain when there are too many calls but method is stubbed too" do
+ @mock.stub(:message).and_return :stub_result
+ @mock.message.should == @return_values[0]
+ @mock.message.should == @return_values[1]
+ @mock.message.should == @return_values[2]
+ @mock.message.should == :stub_result
+ expect { @mock.rspec_verify }.to_not raise_error(RSpec::Mocks::MockExpectationError)
+ end
end
describe "a Mock expectation with multiple return values with a specified count equal to the number of values" do
@@ -56,7 +65,7 @@ module Mocks
@mock.message.should == @return_values[0]
@mock.message.should == @return_values[1]
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 2 times|
)
end
@@ -68,7 +77,20 @@ module Mocks
@mock.message.should == @return_values[2]
@mock.message.should == @return_values[2]
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
+ %Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 4 times|
+ )
+ end
+
+ it "complains when there are too many calls and method is stubbed too" do
+ third = Object.new
+ @mock.stub(:message).and_return :stub_result
+ @mock.message.should == @return_values[0]
+ @mock.message.should == @return_values[1]
+ @mock.message.should == @return_values[2]
+ @mock.message.should == :stub_result
+ expect { @mock.rspec_verify }.to raise_error(
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 4 times|
)
end
@@ -79,7 +101,7 @@ module Mocks
@mock = RSpec::Mocks::Mock.new("mock")
@mock.should_receive(:message).at_least(:twice).with(no_args).and_return(11, 22)
end
-
+
it "uses the last return value for subsequent calls" do
@mock.message.should equal(11)
@mock.message.should equal(22)
@@ -90,10 +112,30 @@ module Mocks
it "fails when called less than the specified number" do
@mock.message.should equal(11)
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(no args)\n expected: 2 times\n received: 1 time|
)
end
+
+ context "when method is stubbed too" do
+ before { @mock.stub(:message).and_return :stub_result }
+
+ it "uses the stub return value for subsequent calls" do
+ @mock.message.should equal(11)
+ @mock.message.should equal(22)
+ @mock.message.should equal(:stub_result)
+ @mock.rspec_verify
+ end
+
+ it "fails when called less than the specified number" do
+ @mock.message.should equal(11)
+ expect { @mock.rspec_verify }.to raise_error(
+ RSpec::Mocks::MockExpectationError,
+ %Q|(Mock "mock").message(no args)\n expected: 2 times\n received: 1 time|
+ )
+ end
+ end
+
end
describe "a Mock expectation with multiple return values with a specified count larger than the number of values" do
@@ -101,7 +143,7 @@ module Mocks
@mock = RSpec::Mocks::Mock.new("mock")
@mock.should_receive(:message).exactly(3).times.and_return(11, 22)
end
-
+
it "uses the last return value for subsequent calls" do
@mock.message.should equal(11)
@mock.message.should equal(22)
@@ -112,7 +154,7 @@ module Mocks
it "fails when called less than the specified number" do
@mock.message.should equal(11)
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 1 time|
)
end
@@ -123,10 +165,26 @@ module Mocks
@mock.message.should equal(22)
@mock.message.should equal(22)
expect { @mock.rspec_verify }.to raise_error(
- RSpec::Mocks::MockExpectationError,
+ RSpec::Mocks::MockExpectationError,
%Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 4 times|
)
end
+
+ context "when method is stubbed too" do
+ before { @mock.stub(:message).and_return :stub_result }
+
+ it "fails when called greater than the specified number" do
+ @mock.message.should equal(11)
+ @mock.message.should equal(22)
+ @mock.message.should equal(22)
+ @mock.message.should equal(:stub_result)
+ expect { @mock.rspec_verify }.to raise_error(
+ RSpec::Mocks::MockExpectationError,
+ %Q|(Mock "mock").message(any args)\n expected: 3 times\n received: 4 times|
+ )
+ end
+
+ end
end
end
end

No commit comments for this range

Something went wrong with that request. Please try again.