Permalink
Browse files

add Expectation#including_subclasses

normally, stubbing a class method on a superclass simply makes
calling that method on a subclass be an unexpected invocation.
now you can optionally use the same stub for all subclasses
  • Loading branch information...
1 parent b500ce8 commit 296c99392f10b60c084bbea5db2d7cf875313acc @ccutrer committed Mar 12, 2013
View
@@ -496,6 +496,29 @@ def in_sequence(*sequences)
self
end
+ # Allows the expectation to match for subclasses
+ #
+ # Only applies to expectations on class methods.
+ #
+ # @param [value] to allow this expectation to match for subclasses
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example
+ # class A
+ # def self.something
+ # 'A'
+ # end
+ # end
+ # class B < A
+ # end
+ #
+ # A.stubs(:something).including_subclass.returns('stub')
+ # B.something => "stub"
+ def including_subclasses(value = true)
+ @including_subclasses = value
+ self
+ end
+
# @private
attr_reader :backtrace
@@ -507,6 +530,7 @@ def initialize(mock, expected_method_name, backtrace = nil)
@ordering_constraints = []
@side_effects = []
@cardinality, @invocation_count = Cardinality.exactly(1), 0
+ @including_subclasses = false
@return_values = ReturnValues.new
@yield_parameters = YieldParameters.new
@backtrace = backtrace || caller
@@ -558,6 +582,11 @@ def satisfied?
end
# @private
+ def including_subclasses?
+ @including_subclasses
+ end
+
+ # @private
def invoke
@invocation_count += 1
perform_side_effects()
@@ -2,8 +2,9 @@ module Mocha
class ExpectationList
- def initialize
+ def initialize(klass = nil)
@expectations = []
+ @klass = klass
end
def add(expectation)
@@ -49,10 +50,25 @@ def any?
private
- def matching_expectations(method_name, *arguments)
+ def local_matching_expectations(method_name, *arguments)
@expectations.select { |e| e.match?(method_name, *arguments) }
end
+ def matching_expectations(method_name, *arguments)
+ expectations = local_matching_expectations(method_name, *arguments)
+ if @klass
+ klass = @klass
+ while klass
+ mocha = klass.instance_variable_get(:@mocha)
+ klass = klass.superclass
+ next unless mocha
+ expectations += mocha.__expectations__.send(:local_matching_expectations, method_name, *arguments).
+ select { |expectation| expectation.including_subclasses? }
+ end
+ end
+ expectations
+ end
+
end
end
View
@@ -197,7 +197,9 @@ def responds_like_instance_of(responder_class)
def initialize(mockery, name = nil, &block)
@mockery = mockery
@name = name || DefaultName.new(self)
- @expectations = ExpectationList.new
+ klass = name.instance_variable_get(:@object) if name.is_a?(ImpersonatingName)
+ klass = nil unless klass.is_a?(Class)
+ @expectations = ExpectationList.new(klass)
@everything_stubbed = false
@responder = nil
instance_eval(&block) if block
@@ -72,4 +72,17 @@ def my_class_method
end
assert_equal :original_return_value, klass.send(:my_class_method)
end
+
+ def test_should_allow_including_subclasses_in_stub
+ superklass = Class.new do
+ class << self
+ def my_class_method
+ :original_return_value
+ end
+ end
+ end
+ klass = Class.new(superklass)
+ superklass.stubs(:my_class_method).including_subclasses.returns(:new_return_value)
+ assert_equal :new_return_value, klass.my_class_method
+ end
end

0 comments on commit 296c993

Please sign in to comment.