diff --git a/lib/mocha/mock.rb b/lib/mocha/mock.rb
index 08e0199..704a117 100644
--- a/lib/mocha/mock.rb
+++ b/lib/mocha/mock.rb
@@ -5,13 +5,14 @@ require 'mocha/missing_expectation'
require 'mocha/metaclass'
module Mocha # :nodoc:
-
+
# Traditional mock object.
#
# Methods return an Expectation which can be further modified by methods on Expectation.
class Mock
-
+
# :call-seq: expects(method_name) -> expectation
+ # expects.method_name(*args) -> expectation
# expects(method_names) -> last expectation
#
# Adds an expectation that a method identified by +method_name+ symbol must be called exactly once with any parameters.
@@ -34,18 +35,26 @@ module Mocha # :nodoc:
# object.expects(:method1).returns(:result1)
# object.expects(:method2).returns(:result2)
#
+ # Additionally, a pseudo-call syntax is provided for convenience, such that the following
+ # lines are equivalent:
+ # object.expects.method1("some", :values)
+ # object.expects(:method1).with("some", :values)
+ #
# Aliased by \_\_expects\_\_
- def expects(method_name_or_hash, backtrace = nil)
+ def expects(method_name_or_hash = nil, backtrace = nil)
if method_name_or_hash.is_a?(Hash) then
method_name_or_hash.each do |method_name, return_value|
add_expectation(Expectation.new(self, method_name, backtrace).returns(return_value))
end
+ elsif method_name_or_hash.nil?
+ PseudoCall.new(self, Expectation)
else
add_expectation(Expectation.new(self, method_name_or_hash, backtrace))
end
end
-
+
# :call-seq: stubs(method_name) -> expectation
+ # stubs.method_name(*args) -> expectation
# stubs(method_names) -> last expectation
#
# Adds an expectation that a method identified by +method_name+ symbol may be called any number of times with any parameters.
@@ -65,17 +74,24 @@ module Mocha # :nodoc:
# object.stubs(:method1).returns(:result1)
# object.stubs(:method2).returns(:result2)
#
+ # Additionally, a pseudo-call syntax is provided for convenience, such that the following
+ # lines are equivalent:
+ # object.stubs.method1("some", :values)
+ # object.stubs(:method1).with("some", :values)
+ #
# Aliased by \_\_stubs\_\_
- def stubs(method_name_or_hash, backtrace = nil)
+ def stubs(method_name_or_hash = nil, backtrace = nil)
if method_name_or_hash.is_a?(Hash) then
method_name_or_hash.each do |method_name, return_value|
add_expectation(Stub.new(self, method_name, backtrace).returns(return_value))
end
+ elsif method_name_or_hash.nil?
+ PseudoCall.new(self, Stub)
else
add_expectation(Stub.new(self, method_name_or_hash, backtrace))
end
end
-
+
# :call-seq: responds_like(responder) -> mock
#
# Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
@@ -120,9 +136,9 @@ module Mocha # :nodoc:
@responder = object
self
end
-
+
# :stopdoc:
-
+
def initialize(stub_everything = false, name = nil)
@stub_everything = stub_everything
@mock_name = name
@@ -131,11 +147,11 @@ module Mocha # :nodoc:
end
attr_reader :stub_everything, :expectations
-
+
alias_method :__expects__, :expects
alias_method :__stubs__, :stubs
-
+
alias_method :quacks_like, :responds_like
def add_expectation(expectation)
@@ -158,7 +174,7 @@ module Mocha # :nodoc:
unexpected_method_called(symbol, *arguments)
end
end
-
+
def respond_to?(symbol)
if @responder then
@responder.respond_to?(symbol)
@@ -166,21 +182,21 @@ module Mocha # :nodoc:
@expectations.respond_to?(symbol)
end
end
-
+
def unexpected_method_called(symbol, *arguments)
MissingExpectation.new(self, symbol).with(*arguments).verify
end
-
+
def verify(&block)
@expectations.verify(&block)
end
-
+
def mocha_inspect
address = self.__id__ * 2
address += 0x100000000 if address < 0
@mock_name ? "#" : "#"
end
-
+
def inspect
mocha_inspect
end
@@ -193,4 +209,17 @@ module Mocha # :nodoc:
end
+ class PseudoCall
+ # Turn this class into a blank slate
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
+
+ def initialize(mock, expectation_class)
+ @mock = mock
+ @expectation_class = expectation_class
+ end
+
+ def method_missing(method_name, *args)
+ @mock.add_expectation(@expectation_class.new(@mock, method_name, nil))
+ end
+ end
end
diff --git a/test/unit/mock_test.rb b/test/unit/mock_test.rb
index a1710a5..ddc0e82 100644
--- a/test/unit/mock_test.rb
+++ b/test/unit/mock_test.rb
@@ -4,16 +4,16 @@ require 'mocha/expectation_error'
require 'set'
class MockTest < Test::Unit::TestCase
-
+
include Mocha
-
+
def test_should_set_single_expectation
mock = Mock.new
mock.expects(:method1).returns(1)
assert_nothing_raised(ExpectationError) do
assert_equal 1, mock.method1
end
- end
+ end
def test_should_build_and_store_expectations
mock = Mock.new
@@ -21,22 +21,22 @@ class MockTest < Test::Unit::TestCase
assert_not_nil expectation
assert_equal [expectation], mock.expectations.to_a
end
-
+
def test_should_not_stub_everything_by_default
mock = Mock.new
assert_equal false, mock.stub_everything
end
-
+
def test_should_stub_everything
mock = Mock.new(stub_everything = true)
assert_equal true, mock.stub_everything
end
-
+
def test_should_display_object_id_for_mocha_inspect_if_mock_has_no_name
mock = Mock.new
assert_match Regexp.new("^#$"), mock.mocha_inspect
end
-
+
def test_should_display_name_for_mocha_inspect_if_mock_has_name
mock = Mock.new(false, 'named_mock')
assert_equal "#", mock.mocha_inspect
@@ -46,7 +46,7 @@ class MockTest < Test::Unit::TestCase
mock = Mock.new
assert_match Regexp.new("^#$"), mock.inspect
end
-
+
def test_should_display_name_for_inspect_if_mock_has_name
mock = Mock.new(false, 'named_mock')
assert_equal "#", mock.inspect
@@ -56,12 +56,12 @@ class MockTest < Test::Unit::TestCase
mock = Mock.new
assert_nothing_raised(ExpectationError) { mock.extend(Module.new) }
end
-
+
def test_should_be_equal
mock = Mock.new
assert_equal true, mock.eql?(mock)
end
-
+
def test_should_be_able_to_mock_standard_object_methods
mock = Mock.new
object_methods = STANDARD_OBJECT_PUBLIC_INSTANCE_METHODS.reject { |m| m =~ /^__.*__$/ }.sort
@@ -76,42 +76,42 @@ class MockTest < Test::Unit::TestCase
object_methods.each { |method| mock.__stubs__(method.to_sym).returns(method) }
object_methods.each { |method| assert_equal method, mock.__send__(method.to_sym) }
end
-
+
def test_should_create_and_add_expectations
mock = Mock.new
expectation1 = mock.expects(:method1)
expectation2 = mock.expects(:method2)
assert_equal [expectation1, expectation2].to_set, mock.expectations.to_set
end
-
+
def test_should_pass_backtrace_into_expectation
mock = Mock.new
backtrace = Object.new
expectation = mock.expects(:method1, backtrace)
assert_equal backtrace, expectation.backtrace
end
-
+
def test_should_pass_backtrace_into_stub
mock = Mock.new
backtrace = Object.new
stub = mock.stubs(:method1, backtrace)
assert_equal backtrace, stub.backtrace
end
-
+
def test_should_create_and_add_stubs
mock = Mock.new
stub1 = mock.stubs(:method1)
stub2 = mock.stubs(:method2)
assert_equal [stub1, stub2].to_set, mock.expectations.to_set
end
-
+
def test_should_invoke_expectation_and_return_result
mock = Mock.new
mock.expects(:my_method).returns(:result)
result = mock.my_method
assert_equal :result, result
end
-
+
def test_should_not_raise_error_if_stubbing_everything
mock = Mock.new(stub_everything = true)
result = nil
@@ -120,7 +120,7 @@ class MockTest < Test::Unit::TestCase
end
assert_nil result
end
-
+
def test_should_raise_assertion_error_for_unexpected_method_call
mock = Mock.new
error = assert_raise(ExpectationError) do
@@ -130,7 +130,7 @@ class MockTest < Test::Unit::TestCase
assert_match(/argument1/, error.message)
assert_match(/argument2/, error.message)
end
-
+
def test_should_indicate_unexpected_method_called
mock = Mock.new
class << mock
@@ -143,7 +143,7 @@ class MockTest < Test::Unit::TestCase
assert_equal :my_method, mock.symbol
assert_equal [:argument1, :argument2], mock.arguments
end
-
+
def test_should_verify_that_all_expectations_have_been_fulfilled
mock = Mock.new
mock.expects(:method1)
@@ -153,14 +153,14 @@ class MockTest < Test::Unit::TestCase
mock.verify
end
end
-
+
def test_should_report_possible_expectations
mock = Mock.new
mock.expects(:expected_method).with(1)
exception = assert_raise(ExpectationError) { mock.expected_method(2) }
assert_equal "#{mock.mocha_inspect}.expected_method(2) - expected calls: 0, actual calls: 1\nSimilar expectations:\n#{mock.mocha_inspect}.expected_method(1)", exception.message
end
-
+
def test_should_pass_block_through_to_expectations_verify_method
mock = Mock.new
expected_expectation = mock.expects(:method1)
@@ -169,7 +169,7 @@ class MockTest < Test::Unit::TestCase
mock.verify() { |expectation| expectations << expectation }
assert_equal [expected_expectation], expectations
end
-
+
def test_should_yield_supplied_parameters_to_block
mock = Mock.new
parameters_for_yield = [1, 2, 3]
@@ -178,35 +178,35 @@ class MockTest < Test::Unit::TestCase
mock.method1() { |*parameters| yielded_parameters = parameters }
assert_equal parameters_for_yield, yielded_parameters
end
-
+
def test_should_set_up_multiple_expectations_with_return_values
mock = Mock.new
mock.expects(:method1 => :result1, :method2 => :result2)
assert_equal :result1, mock.method1
assert_equal :result2, mock.method2
end
-
+
def test_should_set_up_multiple_stubs_with_return_values
mock = Mock.new
mock.stubs(:method1 => :result1, :method2 => :result2)
assert_equal :result1, mock.method1
assert_equal :result2, mock.method2
end
-
+
def test_should_keep_returning_specified_value_for_stubs
mock = Mock.new
mock.stubs(:method1).returns(1)
assert_equal 1, mock.method1
assert_equal 1, mock.method1
end
-
+
def test_should_keep_returning_specified_value_for_expects
mock = Mock.new
mock.expects(:method1).times(2).returns(1)
assert_equal 1, mock.method1
assert_equal 1, mock.method1
end
-
+
def test_should_match_most_recent_call_to_expects
mock = Mock.new
mock.expects(:method1).returns(0)
@@ -234,18 +234,18 @@ class MockTest < Test::Unit::TestCase
mock.stubs(:method1).returns(1)
assert_equal 1, mock.method1
end
-
+
def test_should_respond_to_expected_method
mock = Mock.new
mock.expects(:method1)
assert_equal true, mock.respond_to?(:method1)
end
-
+
def test_should_not_respond_to_unexpected_method
mock = Mock.new
assert_equal false, mock.respond_to?(:method1)
end
-
+
def test_should_respond_to_methods_which_the_responder_does_responds_to
instance = Class.new do
define_method(:respond_to?) { true }
@@ -254,7 +254,7 @@ class MockTest < Test::Unit::TestCase
mock.responds_like(instance)
assert_equal true, mock.respond_to?(:invoked_method)
end
-
+
def test_should_not_respond_to_methods_which_the_responder_does_not_responds_to
instance = Class.new do
define_method(:respond_to?) { false }
@@ -263,12 +263,12 @@ class MockTest < Test::Unit::TestCase
mock.responds_like(instance)
assert_equal false, mock.respond_to?(:invoked_method)
end
-
+
def test_should_return_itself_to_allow_method_chaining
mock = Mock.new
assert_same mock.responds_like(Object.new), mock
end
-
+
def test_should_not_raise_no_method_error_if_mock_is_not_restricted_to_respond_like_a_responder
instance = Class.new do
define_method(:respond_to?) { true }
@@ -277,7 +277,7 @@ class MockTest < Test::Unit::TestCase
mock.stubs(:invoked_method)
assert_nothing_raised(NoMethodError) { mock.invoked_method }
end
-
+
def test_should_not_raise_no_method_error_if_responder_does_respond_to_invoked_method
instance = Class.new do
define_method(:respond_to?) { true }
@@ -287,7 +287,7 @@ class MockTest < Test::Unit::TestCase
mock.stubs(:invoked_method)
assert_nothing_raised(NoMethodError) { mock.invoked_method }
end
-
+
def test_should_raise_no_method_error_if_responder_does_not_respond_to_invoked_method
instance = Class.new do
define_method(:respond_to?) { false }
@@ -298,7 +298,7 @@ class MockTest < Test::Unit::TestCase
mock.stubs(:invoked_method)
assert_raises(NoMethodError) { mock.invoked_method }
end
-
+
def test_should_raise_no_method_error_with_message_indicating_that_mock_is_constrained_to_respond_like_responder
instance = Class.new do
define_method(:respond_to?) { false }
@@ -313,4 +313,26 @@ class MockTest < Test::Unit::TestCase
assert_match(/which responds like mocha_inspect/, e.message)
end
end
-end
\ No newline at end of file
+
+ def test_should_create_and_store_expectations_given_as_pseudo_calls
+ mock = Mock.new
+ expectation1 = mock.expects.method1
+ expectation2 = mock.expects.method2
+ assert_equal [expectation1, expectation2].to_set, mock.expectations.to_set
+ end
+
+ def test_should_create_and_add_stubs_given_as_pseudo_calls
+ mock = Mock.new
+ stub1 = mock.stubs.method1
+ stub2 = mock.stubs.method2
+ assert_equal [stub1, stub2].to_set, mock.expectations.to_set
+ end
+
+ def test_should_treat_pseudo_call_parameters_as_matcher_parameters
+ mock = Mock.new
+ expectation = mock.expects.method1(1, "two", :three)
+ stub = mock.expects.method2(:four)
+ assert expectation.match?(:method1, 1, "two", :three)
+ assert stub.match?(:method2, :four)
+ end
+end