Skip to content

Commit

Permalink
Change of API, including removal of legacy expect_call and stub_call …
Browse files Browse the repository at this point in the history
…methods

darcs-hash:20051014095036-9ce57-53e3fbaa29280b606d5202dc756e378a30da7174.gz
  • Loading branch information
Steve committed Oct 14, 2005
1 parent 3d7d8fd commit 95f554a
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 92 deletions.
59 changes: 48 additions & 11 deletions rmock.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
# = RMock - A Mock Object library inspired by JMock
#
# Copyright (c) 2005 Steve Purcell
# Licenced under the same terms as Ruby itself
#
# == Introduction
#
# An instance of RMock::Mock can be programmed with responses to
# methods calls expected during the course of a unit test. At the
# end of the test, the instance can verify whether its expectations
# were met, signalling a test failure if they were not.
#
# Mocks distinguish between 'expected' method calls, which trigger
# test failures if they are not made, and 'stub' method calls, which
# are not verified. 'Expected' calls are typically those considered
# critical to the proper use of the mocked class, and 'stub' calls are
# those considered more flexible in their use.
#
# == Example
#
# We are testing a controller for the air pump in a new automatic
# bicycle tyre inflator:
#
# class PumpTest < Test::Unit::TestCase
#
# def test_inflates_in_5psi_increments
# gauge_mock = RMock::Mock.new
# gauge_mock.expects.pressure?.as { 95 }
# end
#
# gauge_mock.use do |gauge|
# pump = Pump.new(pressure_gauge)
# pump.inflate_to(110)
# end
# end
#


require 'test/unit'

module RMock
Expand All @@ -16,8 +54,12 @@ def initialize &block
block.call(self) if block
end

def stub()
CallCapturer.new { |meth, *args| stub_call(meth, *args) }
def stubs(&block)
CallCapturer.new(method(:stub_call))
end

def expects(&block)
CallCapturer.new(method(:expect_call))
end

def stub_call(method_name, *argspec)
Expand Down Expand Up @@ -88,7 +130,7 @@ def to_s
@argspec.inspect
end

def will(&block)
def as(&block)
@response = block
end
end
Expand Down Expand Up @@ -122,16 +164,11 @@ def call(*args, &block)
end

class CallCapturer
def initialize(&on_call)
def initialize(on_call)
@on_call = on_call
end
public_methods.each do |meth|
next if %w(__id__ __send__ method_missing).include?(meth)
eval <<-EOF
def #{meth}(*args)
@on_call.call(:#{meth}, *args)
end
EOF
public_instance_methods.each do |meth|
undef_method(meth) unless %w(__id__ __send__ method_missing).include?(meth)
end
def method_missing(meth, *args)
@on_call.call(meth, *args)
Expand Down
129 changes: 48 additions & 81 deletions rmock_tests.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
$VERBOSE = true
$VERBOSE = true if $0 == __FILE__

require 'test/unit'
require 'rmock'
Expand All @@ -13,176 +13,143 @@ class MockTest < Test::Unit::TestCase

def test_stub_call_with_no_arguments_returns_nil
mock = Mock.new
mock.stub_call(:ping)
mock.stubs.ping
assert_nil mock.proxy.ping
end

def test_stub_call_with_no_arguments_will_return_preset_value
mock = Mock.new
mock.stub_call(:ping).will {'pong'}
mock.stubs.ping.as {'pong'}
assert_equal 'pong', mock.proxy.ping
end

def test_can_construct_mock_with_a_block
mock = Mock.new do |m|
m.stub_call(:ping).will {'pong'}
m.stubs.ping.as {'pong'}
end
assert_equal 'pong', mock.proxy.ping
end

def test_error_raised_if_missing_stub_invoked # TODO: assertion error here?
def test_error_raised_if_missing_mock_method_invoked
proxy = Mock.new.proxy
assert_raise NoMethodError do proxy.ping end
end

def test_verify_after_calling_no_stubs_does_nothing
Mock.new.verify
Mock.new { |m| m.stub_call(:ping) }.verify
Mock.new { |m| m.stubs.ping }.verify
end

def test_verify_after_calling_stubs_does_nothing
mock = Mock.new { |m| m.stub_call(:ping) }
mock = Mock.new do |m| m.stubs.ping end
mock.proxy.ping
mock.verify
end

def test_can_expect_and_call_method_with_no_arguments
mock = Mock.new do |m|
m.expect_call(:bing)
end
mock = Mock.new do |m| m.expects.bing end
assert_nil mock.proxy.bing
end

def test_verify_after_calling_expected_method_with_no_args
mock = Mock.new do |m|
m.expect_call(:bing)
end
mock = Mock.new do |m| m.expects.bing end
mock.proxy.bing
mock.verify
end

def test_verify_fails_when_expected_method_not_called
mock = Mock.new do |m|
m.expect_call(:bing)
end
mock = Mock.new do |m| m.expects.bing end
assert_raise AssertionFailedError do mock.verify end
end

def test_can_call_a_stub_twice
def test_can_use_mock_with_block_in_order_to_have_verify_called_automatically
mock = Mock.new do |m|
m.stub_call(:bing).will {'crosby'}
m.expects.some_method
m.expects.some_other_method
end
assert_raise AssertionFailedError do
mock.use { |o| o.some_method }
end
end

def test_can_call_a_stub_twice
mock = Mock.new do |m| m.stubs.bing.as {'crosby'} end
2.times do assert_equal 'crosby', mock.proxy.bing end
end

def test_can_stub_a_method_with_an_argument
mock = Mock.new do |m|
m.stub_call(:bing, 'who?').will {'crosby'}
end
mock = Mock.new do |m| m.stubs.bing('who?').as {'crosby'} end
assert_equal 'crosby', mock.proxy.bing('who?')
end

def test_can_stub_a_method_twice_with_different_args
mock = Mock.new do |m|
m.stub_call(:last_name?, 'marlon').will {'brando'}
m.stub_call(:last_name?, 'jimmy').will {'cagney'}
m.stubs.last_name?('marlon').as {'brando'}
m.stubs.last_name?('jimmy').as {'cagney'}
end
assert_equal 'cagney', mock.proxy.last_name?('jimmy')
assert_equal 'brando', mock.proxy.last_name?('marlon')
end

def test_error_raised_if_expected_method_called_twice
mock = Mock.new do |m|
m.expect_call(:some_method)
def test_can_expect_a_method_with_an_argument
mock = Mock.new
mock.expects.who_am_i?('Jackie').as { 'Chan' }
mock.use do |o|
assert_equal 'Chan', o.who_am_i?('Jackie')
end
mock.proxy.some_method
assert_raise AssertionFailedError do mock.proxy.some_method end
end

def test_can_use_mock_with_block_in_order_to_have_verify_called_automatically
mock = Mock.new do |m|
m.expect_call(:some_method)
m.expect_call(:some_other_method)
end
assert_raise AssertionFailedError do
mock.use { |o| o.some_method }
end
def test_error_raised_if_expected_method_called_twice
mock = Mock.new do |m| m.expects.some_method end
mock.proxy.some_method
assert_raise AssertionFailedError do mock.proxy.some_method end
end

def test_can_stub_pre_existing_methods
mock = Mock.new do |m|
m.stub_call(:to_s).will {'foobar'}
end
mock = Mock.new do |m| m.stubs.to_s.as {'foobar'} end
assert_equal 'foobar', mock.proxy.to_s
end

def test_can_stub_call_that_expects_a_block
mock = Mock.new do |m|
m.stub_call(:each, Proc)
end
mock = Mock.new do |m| m.stubs.each(Proc) end
mock.proxy.each {}
end

def test_error_raised_if_block_not_provided_to_stubbed_method_that_wants_a_block
mock = Mock.new do |m|
m.stub_call(:each, Proc)
end
mock = Mock.new do |m| m.stubs.each(Proc) end
assert_raise AssertionFailedError do
mock.proxy.each
end
end

def test_can_define_stubs_using_a_pseudo_call
mock = Mock.new do |m|
m.stub.ping.will { 'pong' }
end
assert_equal 'pong', mock.proxy.ping
end

def test_can_define_stubs_using_a_pseudo_call_with_params
def test_can_use_ranges_to_specify_argument_matches
mock = Mock.new do |m|
m.stub.ping('one').will { 'two' }
m.stub.ping('three').will { 'four' }
m.stubs.between_1_and_5?(1..5).as { true }
m.stubs.between_1_and_5?(6..10).as { false }
end
assert_equal 'two', mock.proxy.ping('one')
end

def test_can_define_stubs_for_object_methods_using_pseudo_calls
mock = Mock.new do |m|
m.stub.to_s.will { 'stringified' }
mock.use do |o|
assert_equal true, o.between_1_and_5?(3)
assert_equal false, o.between_1_and_5?(7)
end
assert_equal 'stringified', mock.proxy.to_s
end

def test_can_use_ranges_to_specify_argument_matches
mock = Mock.new do |m|
m.stub_call(:between_1_and_5?, 1..5).will { true }
m.stub_call(:between_1_and_5?, 6..10).will { false }
end
mock.use do |proxy|
assert_equal true, proxy.between_1_and_5?(3)
assert_equal false, proxy.between_1_and_5?(7)
end
def test_can_stub_constants
mock = Mock.new do |m| m.stubs.FOOBAR.as { "jimini" } end
assert_equal 'jimini', mock.proxy.FOOBAR
end

def test_can_use_ranges_in_pseudo_calls_to_specify_argument_matches
mock = Mock.new do |m|
m.stub.between_1_and_5?(1..5).will { true }
m.stub.between_1_and_5?(6..10).will { false }
end
mock.use do |proxy|
assert_equal true, proxy.between_1_and_5?(3)
assert_equal false, proxy.between_1_and_5?(7)
end
def test_can_expect_constants
mock = Mock.new do |m| m.expects.FOOBAR.as { "jimini" } end
assert_equal 'jimini', mock.proxy.FOOBAR
end

end


# TODO:
# * Clearer error messages
# * Mocking constants
# * Namespaces for constants
# * Intercepting top-level calls such as File#open
# * Explicit test for use of === in arg matching
# * Allow specification of call order
end

0 comments on commit 95f554a

Please sign in to comment.