mocha 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -4
- data/RELEASE +32 -0
- data/Rakefile +3 -3
- data/examples/misc.rb +36 -0
- data/examples/mocha.rb +26 -0
- data/examples/stubba.rb +65 -0
- data/lib/mocha.rb +17 -5
- data/lib/{stubba → mocha}/any_instance_method.rb +2 -2
- data/lib/mocha/auto_verify.rb +7 -7
- data/lib/{stubba → mocha}/central.rb +2 -2
- data/lib/{stubba → mocha}/class_method.rb +7 -10
- data/lib/mocha/expectation.rb +88 -33
- data/lib/mocha/expectation_error.rb +6 -0
- data/lib/mocha/inspect.rb +1 -1
- data/lib/mocha/instance_method.rb +8 -0
- data/lib/mocha/metaclass.rb +1 -1
- data/lib/mocha/mock.rb +8 -8
- data/lib/mocha/mock_methods.rb +60 -16
- data/lib/{stubba → mocha}/object.rb +8 -10
- data/lib/mocha/setup_and_teardown.rb +23 -0
- data/lib/mocha/standalone.rb +30 -0
- data/lib/mocha/test_case_adapter.rb +49 -0
- data/lib/mocha_standalone.rb +2 -0
- data/lib/stubba.rb +2 -8
- data/test/all_tests.rb +9 -10
- data/test/method_definer.rb +2 -2
- data/test/{stubba → mocha}/any_instance_method_test.rb +1 -3
- data/test/mocha/auto_verify_test.rb +9 -10
- data/test/{stubba → mocha}/central_test.rb +5 -4
- data/test/{stubba → mocha}/class_method_test.rb +40 -10
- data/test/mocha/expectation_test.rb +144 -67
- data/test/mocha/inspect_test.rb +12 -1
- data/test/mocha/metaclass_test.rb +22 -0
- data/test/mocha/mock_methods_test.rb +65 -7
- data/test/mocha/mock_test.rb +41 -4
- data/test/{stubba → mocha}/object_test.rb +9 -9
- data/test/mocha/setup_and_teardown_test.rb +76 -0
- data/test/mocha_acceptance_test.rb +8 -8
- data/test/mocha_test_result_integration_test.rb +5 -6
- data/test/standalone_acceptance_test.rb +110 -0
- data/test/stubba_acceptance_test.rb +2 -2
- data/test/stubba_integration_test.rb +17 -24
- data/test/stubba_test_result_integration_test.rb +5 -6
- metadata +22 -18
- data/lib/shared/backtracefilter.rb +0 -46
- data/lib/smart_test_case.rb +0 -5
- data/lib/smart_test_case/multiple_setup_and_teardown.rb +0 -123
- data/lib/stubba/instance_method.rb +0 -18
- data/lib/stubba/setup_and_teardown.rb +0 -25
- data/test/smart_test_case/multiple_setup_and_teardown_test.rb +0 -192
- data/test/stubba/instance_method_test.rb +0 -46
- data/test/stubba/setup_and_teardown_test.rb +0 -134
data/README
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
= Mocha
|
2
2
|
|
3
|
-
Mocha is a library for mocking and stubbing
|
3
|
+
Mocha is a library for mocking and stubbing using a syntax like that of JMock[http://www.jmock.org], and SchMock[http://rubyforge.org/projects/schmock]. Most commonly Mocha is used in conjunction with Test::Unit[http://www.ruby-doc.org/core/classes/Test/Unit.html], but it can be used in other contexts.
|
4
4
|
|
5
|
-
One of its main advantages is that it allows you to mock and stub methods on _real_ (non-mock) classes and instances. You can for example stub ActiveRecord[http://api.rubyonrails.com/classes/ActiveRecord/Base.html] instance methods like +create+, +save+, +destroy+ and even class methods like +find+ to avoid hitting the database in unit tests.
|
5
|
+
One of its main advantages is that it allows you to mock and stub methods on _real_ (non-mock) classes and instances. You can for example stub ActiveRecord[http://api.rubyonrails.com/classes/ActiveRecord/Base.html] instance methods like +create+, +save+, +destroy+ and even class methods like +find+ to avoid hitting the database in unit tests.
|
6
6
|
|
7
|
-
Mocha provides a unified, simple and readable syntax for both traditional mocking and for mocking with
|
7
|
+
Mocha provides a unified, simple and readable syntax for both traditional mocking and for mocking with _real_ objects.
|
8
8
|
|
9
|
-
Mocha has been harvested from projects at Reevoo[http://www.reevoo.com] by me (James[http://blog.floehopper.org]) and my colleagues Ben[http://www.reevoo.com/blogs/bengriffiths
|
9
|
+
Mocha has been harvested from projects at Reevoo[http://www.reevoo.com] by me (James[http://blog.floehopper.org]) and my colleagues Ben[http://www.reevoo.com/blogs/bengriffiths], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com]. Mocha is in use on real-world Rails[http://www.rubyonrails.org] projects.
|
10
10
|
|
11
11
|
== Download and Installation
|
12
12
|
|
data/RELEASE
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
+
= 0.4.0
|
2
|
+
|
3
|
+
- Allow naming of mocks (patch from Chris Roos).
|
4
|
+
- Specify multiple return values for consecutive calls.
|
5
|
+
- Improved consistency of expectation error messages.
|
6
|
+
- Allow mocking of Object instance methods e.g. kind_of?, type.
|
7
|
+
- Provide aliased versions of #expects and #stubs to allow mocking of these methods.
|
8
|
+
- Added at_least, at_most, at_most_once methods to expectation.
|
9
|
+
- Allow expects and stubs to take a hash of method and return values.
|
10
|
+
- Eliminate warning: "instance variable @yield not initialized" (patch from Xavier Shay).
|
11
|
+
- Restore instance methods on partial mocks (patch from Chris Roos).
|
12
|
+
- Allow stubbing of a method with non-word characters in its name (patch from Paul Battley).
|
13
|
+
- Removed coupling to Test::Unit.
|
14
|
+
- Allow specified exception instance to be raised (patch from Chris Roos).
|
15
|
+
- Make mock object_id appear in hex like normal Ruby inspect (patch from Paul Battley).
|
16
|
+
- Fix path to object.rb in rdoc rake task (patch from Tomas Pospisek).
|
17
|
+
- Reverse order in which expectations are matched, so that last expectation is matched first. This allows e.g. a call to #stubs to be effectively overridden by a call to #expects (patch from Tobias Lutke).
|
18
|
+
- Stubba & SmartTestCase modules incorporated into Mocha module so only need to require 'mocha' - no longer need to require 'stubba'.
|
19
|
+
- AutoMocha removed.
|
20
|
+
|
21
|
+
= 0.3.3
|
22
|
+
|
23
|
+
- Quick bug fix to restore instance methods on partial mocks (for Kevin Clark).
|
24
|
+
|
25
|
+
= 0.3.2
|
26
|
+
|
27
|
+
- Examples added.
|
28
|
+
|
29
|
+
= 0.3.1
|
30
|
+
|
31
|
+
- Dual licensing with MIT license added.
|
32
|
+
|
1
33
|
= 0.3.0
|
2
34
|
|
3
35
|
* Rails plugin.
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake/gempackagetask'
|
|
4
4
|
require 'rake/contrib/sshpublisher'
|
5
5
|
|
6
6
|
module Mocha
|
7
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.4.0"
|
8
8
|
end
|
9
9
|
|
10
10
|
desc "Default task is currently to run all tests"
|
@@ -23,7 +23,7 @@ Rake::RDocTask.new do |task|
|
|
23
23
|
task.rdoc_dir = 'doc'
|
24
24
|
task.template = "html_with_google_analytics"
|
25
25
|
task.options << "--line-numbers" << "--inline-source"
|
26
|
-
task.rdoc_files.include('README', 'RELEASE', 'COPYING', 'MIT-LICENSE', 'agiledox.txt', 'lib/mocha/auto_verify.rb', 'lib/mocha/mock_methods.rb', 'lib/mocha/expectation.rb', 'lib/
|
26
|
+
task.rdoc_files.include('README', 'RELEASE', 'COPYING', 'MIT-LICENSE', 'agiledox.txt', 'lib/mocha/auto_verify.rb', 'lib/mocha/mock_methods.rb', 'lib/mocha/expectation.rb', 'lib/mocha/object.rb')
|
27
27
|
end
|
28
28
|
task :rdoc => :examples
|
29
29
|
|
@@ -88,7 +88,7 @@ specification = Gem::Specification.new do |s|
|
|
88
88
|
s.rdoc_options << '--title' << 'Mocha' << '--main' << 'README' << '--line-numbers'
|
89
89
|
|
90
90
|
s.autorequire = 'mocha'
|
91
|
-
s.files = FileList['{lib,test}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a
|
91
|
+
s.files = FileList['{lib,test,examples}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a
|
92
92
|
s.test_file = "test/all_tests.rb"
|
93
93
|
end
|
94
94
|
|
data/examples/misc.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Mocking a class method
|
2
|
+
|
3
|
+
product = Product.new
|
4
|
+
Product.expects(:find).with(1).returns(product)
|
5
|
+
assert_equal product, Product.find(1)
|
6
|
+
|
7
|
+
# Mocking an instance method on a real object
|
8
|
+
|
9
|
+
product = Product.new
|
10
|
+
product.expects(:save).returns(true)
|
11
|
+
assert product.save
|
12
|
+
|
13
|
+
# Stubbing instance methods on real object
|
14
|
+
|
15
|
+
prices = [stub(:pence => 1000), stub(:pence => 2000)]
|
16
|
+
product = Product.new
|
17
|
+
product.stubs(:prices).returns(prices)
|
18
|
+
assert_equal [1000, 2000], product.prices.collect {|p| p.pence}
|
19
|
+
|
20
|
+
# Stubbing an instance method on all instances of a class
|
21
|
+
|
22
|
+
Product.any_instance.stubs(:name).returns('stubbed_name')
|
23
|
+
product = Product.new
|
24
|
+
assert_equal 'stubbed_name', product.name
|
25
|
+
|
26
|
+
# Traditional mocking
|
27
|
+
|
28
|
+
object = mock()
|
29
|
+
object.expects(:expected_method).with(:p1, :p2).returns(:result)
|
30
|
+
assert_equal :result, object.expected_method(:p1, :p2)
|
31
|
+
|
32
|
+
# Shortcuts
|
33
|
+
|
34
|
+
object = stub(:method1 => :result1, :method2 => :result2)
|
35
|
+
assert_equal :result1, object.method1
|
36
|
+
assert_equal :result2, object.method2
|
data/examples/mocha.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Enterprise
|
2
|
+
|
3
|
+
def initialize(dilithium)
|
4
|
+
@dilithium = dilithium
|
5
|
+
end
|
6
|
+
|
7
|
+
def go(warp_factor)
|
8
|
+
warp_factor.times { @dilithium.nuke(:anti_matter) }
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'rubygems'
|
15
|
+
require 'mocha'
|
16
|
+
|
17
|
+
class EnterpriseTest < Test::Unit::TestCase
|
18
|
+
|
19
|
+
def test_should_boldly_go
|
20
|
+
dilithium = mock()
|
21
|
+
dilithium.expects(:nuke).with(:anti_matter).at_least_once # auto-verified at end of test
|
22
|
+
enterprise = Enterprise.new(dilithium)
|
23
|
+
enterprise.go(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/examples/stubba.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
class Order
|
2
|
+
|
3
|
+
attr_accessor :shipped_on
|
4
|
+
|
5
|
+
def total_cost
|
6
|
+
line_items.inject(0) { |total, line_item| total + line_item.price } + shipping_cost
|
7
|
+
end
|
8
|
+
|
9
|
+
def total_weight
|
10
|
+
line_items.inject(0) { |total, line_item| total + line_item.weight }
|
11
|
+
end
|
12
|
+
|
13
|
+
def shipping_cost
|
14
|
+
total_weight * 5 + 10
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
|
19
|
+
def find_all
|
20
|
+
# Database.connection.execute('select * from orders...
|
21
|
+
end
|
22
|
+
|
23
|
+
def number_shipped_since(date)
|
24
|
+
find_all.select { |order| order.shipped_on > date }.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def unshipped_value
|
28
|
+
find_all.inject(0) { |total, order| order.shipped_on ? total : total + order.total_cost }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'test/unit'
|
36
|
+
require 'rubygems'
|
37
|
+
require 'stubba'
|
38
|
+
|
39
|
+
class OrderTest < Test::Unit::TestCase
|
40
|
+
|
41
|
+
# illustrates stubbing instance method
|
42
|
+
def test_should_calculate_shipping_cost_based_on_total_weight
|
43
|
+
order = Order.new
|
44
|
+
order.stubs(:total_weight).returns(10)
|
45
|
+
assert_equal 60, order.shipping_cost
|
46
|
+
end
|
47
|
+
|
48
|
+
# illustrates stubbing class method
|
49
|
+
def test_should_count_number_of_orders_shipped_after_specified_date
|
50
|
+
now = Time.now; week_in_secs = 7 * 24 * 60 * 60
|
51
|
+
order_1 = Order.new; order_1.shipped_on = now - 1 * week_in_secs
|
52
|
+
order_2 = Order.new; order_2.shipped_on = now - 3 * week_in_secs
|
53
|
+
Order.stubs(:find_all).returns([order_1, order_2])
|
54
|
+
assert_equal 1, Order.number_shipped_since(now - 2 * week_in_secs)
|
55
|
+
end
|
56
|
+
|
57
|
+
# illustrates stubbing instance method for all instances of a class
|
58
|
+
def test_should_calculate_value_of_unshipped_orders
|
59
|
+
Order.stubs(:find_all).returns([Order.new, Order.new, Order.new])
|
60
|
+
Order.any_instance.stubs(:shipped_on).returns(nil)
|
61
|
+
Order.any_instance.stubs(:total_cost).returns(10)
|
62
|
+
assert_equal 30, Order.unshipped_value
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/mocha.rb
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
-
require '
|
2
|
-
require 'mocha/
|
3
|
-
|
1
|
+
require 'mocha_standalone'
|
2
|
+
require 'mocha/test_case_adapter'
|
3
|
+
|
4
|
+
require 'test/unit/testcase'
|
5
|
+
|
6
|
+
module Test
|
7
|
+
|
8
|
+
module Unit
|
9
|
+
|
10
|
+
class TestCase
|
11
|
+
|
12
|
+
include Mocha::Standalone
|
13
|
+
include Mocha::TestCaseAdapter
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
4
18
|
|
5
|
-
class Test::Unit::TestCase
|
6
|
-
include Mocha::AutoVerify unless ancestors.include?(Mocha::AutoVerify)
|
7
19
|
end
|
data/lib/mocha/auto_verify.rb
CHANGED
@@ -6,12 +6,9 @@ require 'mocha/mock'
|
|
6
6
|
#
|
7
7
|
# See Mocha::MockMethods for methods on mock objects.
|
8
8
|
module Mocha
|
9
|
+
|
9
10
|
module AutoVerify
|
10
11
|
|
11
|
-
def self.included(base) # :nodoc:
|
12
|
-
base.add_teardown_method(:teardown_mocks)
|
13
|
-
end
|
14
|
-
|
15
12
|
def mocks # :nodoc:
|
16
13
|
@mocks ||= []
|
17
14
|
end
|
@@ -19,7 +16,7 @@ module Mocha
|
|
19
16
|
def reset_mocks # :nodoc:
|
20
17
|
@mocks = nil
|
21
18
|
end
|
22
|
-
|
19
|
+
|
23
20
|
# :call-seq: mock(name) -> mock object
|
24
21
|
# mock(expected_methods = {}) -> mock object
|
25
22
|
# mock(name, expected_methods = {}) -> mock object
|
@@ -83,9 +80,12 @@ module Mocha
|
|
83
80
|
name, expectations = name_and_expectations_from_args(args)
|
84
81
|
build_mock_with_expectations(:stub_everything, expectations, name)
|
85
82
|
end
|
83
|
+
|
84
|
+
def verify_mocks # :nodoc:
|
85
|
+
mocks.each { |mock| mock.verify { yield if block_given? } }
|
86
|
+
end
|
86
87
|
|
87
88
|
def teardown_mocks # :nodoc:
|
88
|
-
mocks.each { |mock| mock.verify { add_assertion } }
|
89
89
|
reset_mocks
|
90
90
|
end
|
91
91
|
|
@@ -94,7 +94,7 @@ module Mocha
|
|
94
94
|
expectation_type = :stubs if expectation_type == :stub_everything
|
95
95
|
mock = Mocha::Mock.new(stub_everything, name)
|
96
96
|
expectations.each do |method, result|
|
97
|
-
mock.
|
97
|
+
mock.__send__(expectation_type, method).returns(result)
|
98
98
|
end
|
99
99
|
mocks << mock
|
100
100
|
mock
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module Mocha
|
2
2
|
|
3
3
|
class Central
|
4
4
|
|
@@ -20,7 +20,7 @@ module Stubba
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def unique_mocks
|
23
|
-
stubba_methods.
|
23
|
+
stubba_methods.inject({}) { |mocks, method| mocks[method.mock.__id__] = method.mock; mocks }.values
|
24
24
|
end
|
25
25
|
|
26
26
|
def unstub_all
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'mocha/metaclass'
|
2
2
|
|
3
|
-
module
|
3
|
+
module Mocha
|
4
4
|
|
5
5
|
class ClassMethod
|
6
6
|
|
@@ -26,29 +26,26 @@ module Stubba
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def hide_original_method
|
29
|
-
stubbee.
|
29
|
+
stubbee.__metaclass__.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.__metaclass__.method_defined?(method)
|
30
30
|
end
|
31
31
|
|
32
32
|
def define_new_method
|
33
|
-
stubbee.
|
33
|
+
stubbee.__metaclass__.class_eval "def #{method}(*args, &block); mocha.method_missing(:#{method}, *args, &block); end"
|
34
34
|
end
|
35
35
|
|
36
36
|
def remove_new_method
|
37
|
-
stubbee.
|
37
|
+
stubbee.__metaclass__.class_eval "remove_method :#{method}"
|
38
38
|
end
|
39
39
|
|
40
40
|
def restore_original_method
|
41
|
-
stubbee.
|
41
|
+
stubbee.__metaclass__.class_eval "alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}" if stubbee.__metaclass__.method_defined?(hidden_method)
|
42
42
|
end
|
43
43
|
|
44
44
|
def hidden_method
|
45
|
-
|
45
|
+
method_name = method.to_s.gsub(/\W/) {|s| "_substituted_character_#{s[0]}_" }
|
46
|
+
"__stubba__#{method_name}__stubba__"
|
46
47
|
end
|
47
48
|
|
48
|
-
def cannot_replace_method_error
|
49
|
-
Test::Unit::AssertionFailedError.new("Cannot replace #{method} because it is not defined in #{stubbee}.")
|
50
|
-
end
|
51
|
-
|
52
49
|
def eql?(other)
|
53
50
|
return false unless (other.class == self.class)
|
54
51
|
(stubbee == other.stubbee) and (method == other.method)
|
data/lib/mocha/expectation.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
require 'mocha/infinite_range'
|
2
2
|
require 'mocha/pretty_parameters'
|
3
|
+
require 'mocha/expectation_error'
|
4
|
+
|
5
|
+
class Object
|
6
|
+
|
7
|
+
alias_method :__is_a__, :is_a?
|
8
|
+
|
9
|
+
end
|
3
10
|
|
4
11
|
module Mocha
|
5
12
|
# Methods on expectations returned from Mocha::MockMethods#expects and Mocha::MockMethods#stubs
|
@@ -13,19 +20,17 @@ module Mocha
|
|
13
20
|
def ==(other)
|
14
21
|
true
|
15
22
|
end
|
16
|
-
def to_s
|
17
|
-
"** any **"
|
18
|
-
end
|
19
23
|
end
|
20
24
|
|
21
25
|
attr_reader :method_name, :backtrace
|
22
26
|
|
23
|
-
def initialize(method_name, backtrace = nil)
|
24
|
-
@method_name = method_name
|
27
|
+
def initialize(mock, method_name, backtrace = nil)
|
28
|
+
@mock, @method_name = mock, method_name
|
25
29
|
@count = 1
|
26
30
|
@parameters, @parameter_block = AlwaysEqual.new, nil
|
27
31
|
@invoked, @return_value = 0, nil
|
28
32
|
@backtrace = backtrace || caller
|
33
|
+
@yield = nil
|
29
34
|
end
|
30
35
|
|
31
36
|
def yield?
|
@@ -79,11 +84,12 @@ module Mocha
|
|
79
84
|
# object.expected_method # => verify succeeds
|
80
85
|
def never
|
81
86
|
times(0)
|
87
|
+
self
|
82
88
|
end
|
83
89
|
|
84
|
-
# :call-seq: at_least(
|
90
|
+
# :call-seq: at_least(minimum_number_of_times) -> expectation
|
85
91
|
#
|
86
|
-
# Modifies expectation so that the expected method must be called at least a +
|
92
|
+
# Modifies expectation so that the expected method must be called at least a +minimum_number_of_times+.
|
87
93
|
# object = mock()
|
88
94
|
# object.expects(:expected_method).at_least(2)
|
89
95
|
# 3.times { object.expected_method } # => verify succeeds
|
@@ -91,8 +97,8 @@ module Mocha
|
|
91
97
|
# object = mock()
|
92
98
|
# object.expects(:expected_method).at_least(2)
|
93
99
|
# object.expected_method # => verify fails
|
94
|
-
def at_least(
|
95
|
-
times(Range.at_least(
|
100
|
+
def at_least(minimum_number_of_times)
|
101
|
+
times(Range.at_least(minimum_number_of_times))
|
96
102
|
self
|
97
103
|
end
|
98
104
|
|
@@ -111,6 +117,36 @@ module Mocha
|
|
111
117
|
self
|
112
118
|
end
|
113
119
|
|
120
|
+
# :call-seq: at_most(maximum_number_of_times) -> expectation
|
121
|
+
#
|
122
|
+
# Modifies expectation so that the expected method must be called at most a +maximum_number_of_times+.
|
123
|
+
# object = mock()
|
124
|
+
# object.expects(:expected_method).at_most(2)
|
125
|
+
# 2.times { object.expected_method } # => verify succeeds
|
126
|
+
#
|
127
|
+
# object = mock()
|
128
|
+
# object.expects(:expected_method).at_most(2)
|
129
|
+
# 3.times { object.expected_method } # => verify fails
|
130
|
+
def at_most(maximum_number_of_times)
|
131
|
+
times(Range.at_most(maximum_number_of_times))
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
# :call-seq: at_most_once() -> expectation
|
136
|
+
#
|
137
|
+
# Modifies expectation so that the expected method must be called at most once.
|
138
|
+
# object = mock()
|
139
|
+
# object.expects(:expected_method).at_most_once
|
140
|
+
# object.expected_method # => verify succeeds
|
141
|
+
#
|
142
|
+
# object = mock()
|
143
|
+
# object.expects(:expected_method).at_most_once
|
144
|
+
# 2.times { object.expected_method } # => verify fails
|
145
|
+
def at_most_once()
|
146
|
+
at_most(1)
|
147
|
+
self
|
148
|
+
end
|
149
|
+
|
114
150
|
# :call-seq: with(*arguments, ¶meter_block) -> expectation
|
115
151
|
#
|
116
152
|
# Modifies expectation so that the expected method must be called with specified +arguments+.
|
@@ -151,19 +187,25 @@ module Mocha
|
|
151
187
|
end
|
152
188
|
|
153
189
|
# :call-seq: returns(value) -> expectation
|
190
|
+
# :call-seq: returns(*values) -> expectation
|
154
191
|
#
|
155
192
|
# Modifies expectation so that when the expected method is called, it returns the specified +value+.
|
156
193
|
# object = mock()
|
157
|
-
# object.
|
158
|
-
# object.
|
194
|
+
# object.stubs(:stubbed_method).returns('result')
|
195
|
+
# object.stubbed_method # => 'result'
|
196
|
+
# object.stubbed_method # => 'result'
|
197
|
+
# If multiple +values+ are given, these are returned in turn on consecutive calls to the method.
|
198
|
+
# object = mock()
|
199
|
+
# object.stubs(:stubbed_method).returns(1, 2)
|
200
|
+
# object.stubbed_method # => 1
|
201
|
+
# object.stubbed_method # => 2
|
159
202
|
# If +value+ is a Proc, then expected method will return result of calling Proc.
|
160
203
|
# object = mock()
|
161
|
-
#
|
162
|
-
# object.
|
163
|
-
# object.
|
164
|
-
|
165
|
-
|
166
|
-
@return_value = value
|
204
|
+
# object.stubs(:stubbed_method).returns(lambda { rand(100) })
|
205
|
+
# object.stubbed_method # => 41
|
206
|
+
# object.stubbed_method # => 77
|
207
|
+
def returns(*values)
|
208
|
+
@return_value = (values.size > 1) ? lambda { values.shift } : @return_value = values.first
|
167
209
|
self
|
168
210
|
end
|
169
211
|
|
@@ -174,7 +216,7 @@ module Mocha
|
|
174
216
|
# object.expects(:expected_method).raises(Exception, 'message')
|
175
217
|
# object.expected_method # => raises exception of class Exception and with message 'message'
|
176
218
|
def raises(exception = RuntimeError, message = nil)
|
177
|
-
@return_value = lambda{ raise exception, message }
|
219
|
+
@return_value = message ? lambda { raise exception, message } : lambda { raise exception }
|
178
220
|
self
|
179
221
|
end
|
180
222
|
|
@@ -183,22 +225,33 @@ module Mocha
|
|
183
225
|
def invoke
|
184
226
|
@invoked += 1
|
185
227
|
yield(*@parameters_to_yield) if yield? and block_given?
|
186
|
-
@return_value.
|
228
|
+
@return_value.__is_a__(Proc) ? @return_value.call : @return_value
|
187
229
|
end
|
188
230
|
|
189
231
|
def verify
|
190
232
|
yield(self) if block_given?
|
191
233
|
unless (@count === @invoked) then
|
192
|
-
|
193
|
-
|
194
|
-
raise
|
234
|
+
error = ExpectationError.new(error_message(@count, @invoked))
|
235
|
+
error.set_backtrace(filtered_backtrace)
|
236
|
+
raise error
|
195
237
|
end
|
196
238
|
end
|
239
|
+
|
240
|
+
def mocha_lib_directory
|
241
|
+
File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR
|
242
|
+
end
|
243
|
+
|
244
|
+
def filtered_backtrace
|
245
|
+
backtrace.reject { |location| Regexp.new(mocha_lib_directory).match(File.expand_path(location)) }
|
246
|
+
end
|
197
247
|
|
198
|
-
def
|
199
|
-
|
200
|
-
|
201
|
-
|
248
|
+
def method_signature
|
249
|
+
return "#{method_name}" if @parameters.__is_a__(AlwaysEqual)
|
250
|
+
"#{@method_name}(#{PrettyParameters.new(@parameters).pretty})"
|
251
|
+
end
|
252
|
+
|
253
|
+
def error_message(expected_count, actual_count)
|
254
|
+
"#{@mock.mocha_inspect}.#{method_signature} - expected calls: #{expected_count}, actual calls: #{actual_count}"
|
202
255
|
end
|
203
256
|
|
204
257
|
# :startdoc:
|
@@ -217,20 +270,22 @@ module Mocha
|
|
217
270
|
|
218
271
|
class MissingExpectation < Expectation
|
219
272
|
|
220
|
-
def initialize(
|
221
|
-
super
|
222
|
-
@mock, @expectations = mock, expectations
|
273
|
+
def initialize(mock, method_name)
|
274
|
+
super
|
223
275
|
@invoked = true
|
224
276
|
end
|
225
277
|
|
226
278
|
def verify
|
227
|
-
msg =
|
228
|
-
|
229
|
-
|
279
|
+
msg = error_message(0, 1)
|
280
|
+
similar_expectations_list = similar_expectations.collect { |expectation| expectation.method_signature }.join("\n")
|
281
|
+
msg << "\nSimilar expectations:\n#{similar_expectations_list}" unless similar_expectations.empty?
|
282
|
+
error = ExpectationError.new(msg)
|
283
|
+
error.set_backtrace(filtered_backtrace)
|
284
|
+
raise error if @invoked
|
230
285
|
end
|
231
286
|
|
232
287
|
def similar_expectations
|
233
|
-
@expectations.select { |expectation| expectation.method_name == self.method_name }
|
288
|
+
@mock.expectations.select { |expectation| expectation.method_name == self.method_name }
|
234
289
|
end
|
235
290
|
|
236
291
|
end
|