mocha 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|