Class: Object
- Inherits:
- BasicObject
- Defined in:
- lib/motion-spec/mock/method_bind_unbind.rb,
lib/motion-spec/mock/mock.rb,
lib/motion-spec/mock/stub.rb,
lib/motion-spec/mock/proxy.rb,
lib/motion-spec/extensions/object.rb,
lib/motion-spec/extensions/boolean.rb
Overview
The meta-programming that allows us to pop methods on and off for mocking
Instance Method Summary collapse
-
#class_def(name, &block) ⇒ Object
Defines an instance method within a class.
- #false? ⇒ Boolean
-
#meta_def(name, &method_body) ⇒ Object
Adds methods to a metaclass.
- #meta_eval(&block) ⇒ Object
-
#metaclass ⇒ Object
The hidden singleton lurks behind everyone.
-
#mock!(method, options = {}, &block) ⇒ Object
Create a mock method on an object.
-
#proxy!(method, options = {}, &block) ⇒ Object
Creates a proxy method on an object.
- #reset(method_name) ⇒ Object
- #safe_meta_def(name, &method_body) ⇒ Object
- #should(*args, &block) ⇒ Object
- #should_not_call(method) ⇒ Object
-
#stub!(method_name, options = {}, &stubbed) ⇒ Object
Create a stub method on an object.
- #true? ⇒ Boolean
Instance Method Details
#class_def(name, &block) ⇒ Object
Defines an instance method within a class
28 29 30 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 28 def class_def(name, &block) class_eval { define_method name, &block } end |
#false? ⇒ Boolean
7 8 9 |
# File 'lib/motion-spec/extensions/boolean.rb', line 7 def false? false end |
#meta_def(name, &method_body) ⇒ Object
Adds methods to a metaclass
16 17 18 19 20 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 16 def (name, &method_body) do define_method(name) { |*args, &block| method_body.call(*args, &block) } end end |
#meta_eval(&block) ⇒ Object
11 12 13 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 11 def (&block) .instance_eval(&block) end |
#metaclass ⇒ Object
The hidden singleton lurks behind everyone
5 6 7 8 9 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 5 def class << self self end end |
#mock!(method, options = {}, &block) ⇒ Object
Create a mock method on an object. A mock object will place an expectation on behavior and cause a test failure if it’s not fulfilled.
Examples
my_string = "a wooden rabbit"
my_string.mock!(:retreat!, :return => "run away! run away!")
my_string.mock!(:question, :return => "what is the airspeed velocity of an unladen sparrow?")
# test/your_test.rb
my_string.retreat! # => "run away! run away!"
# If we let the test case end at this point, it fails with:
# Unmet expectation: #<Sparrow:1ee7> expected question
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/motion-spec/mock/mock.rb', line 17 def mock!(method, = {}, &block) MotionSpec::Mocks.add([self, method]) behavior = if block_given? lambda do |*args| fail ArgumentError if block.arity >= 0 && args.length != block.arity MotionSpec::Mocks.verify([self, method]) block.call(*args) end elsif ![:yield].nil? lambda do |*_args| MotionSpec::Mocks.verify([self, method]) yield([:yield]) end else lambda do |*_args| MotionSpec::Mocks.verify([self, method]) return [:return] end end method, &behavior end |
#proxy!(method, options = {}, &block) ⇒ Object
Creates a proxy method on an object. In this setup, it places an expectation on an object (like a mock) but still calls the original method. So if you want to make sure the method is called and still return its value, or simply want to invoke the side effects of a method and return a stubbed value, then you can do that.
Examples
class Parrot
def speak!
puts @words
end
def say_this(words)
@words = words
"I shall say #{words}!"
end
end
# => test/your_test.rb
sqawky = Parrot.new
sqawky.proxy!(:say_this)
# Proxy method still calls original method...
sqawky.say_this("hey") # => "I shall say hey!"
sqawky.speak! # => "hey"
sqawky.proxy!(:say_this, "herro!")
# Even though we return a stubbed value...
sqawky.say_this("these words") # => "herro!"
# ...the side effects are still there.
sqawky.speak! # => "these words"
TODO: This implementation is still very rough. Needs refactoring and refining. Won’t work on ActiveRecord attributes, for example.
37 38 39 40 41 42 43 44 45 |
# File 'lib/motion-spec/mock/proxy.rb', line 37 def proxy!(method, = {}, &block) MotionSpec::Mocks.add([self, method]) if respond_to?(method) proxy_existing_method(method, , &block) else proxy_missing_method(method, , &block) end end |
#reset(method_name) ⇒ Object
32 33 34 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 32 def reset(method_name) .restore_original_method(method_name) end |
#safe_meta_def(name, &method_body) ⇒ Object
22 23 24 25 |
# File 'lib/motion-spec/mock/method_bind_unbind.rb', line 22 def (name, &method_body) .remember_original_method(name) (name, &method_body) end |
#should(*args, &block) ⇒ Object
3 4 5 |
# File 'lib/motion-spec/extensions/object.rb', line 3 def should(*args, &block) MotionSpec::Should.new(self).be(*args, &block) end |
#should_not_call(method) ⇒ Object
43 44 45 46 47 |
# File 'lib/motion-spec/mock/mock.rb', line 43 def should_not_call(method) (method) do should.flunk "Umet expectations: #{method} expected to not be called" end end |
#stub!(method_name, options = {}, &stubbed) ⇒ Object
Create a stub method on an object. Simply returns a value for a method call on an object.
Examples
my_string = "a wooden rabbit"
my_string.stub!(:retreat!, :return => "run away! run away!")
# test/your_test.rb
my_string.retreat! # => "run away! run away!"
14 15 16 17 18 19 20 |
# File 'lib/motion-spec/mock/stub.rb', line 14 def stub!(method_name, = {}, &stubbed) MotionSpec::Stubs.add(self, method_name) behavior = (block_given? ? stubbed : -> { return [:return] }) method_name, &behavior end |
#true? ⇒ Boolean
3 4 5 |
# File 'lib/motion-spec/extensions/boolean.rb', line 3 def true? false end |