mocha 0.3.1 → 0.3.2
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 +17 -146
- data/Rakefile +60 -6
- data/lib/mocha.rb +1 -1
- data/lib/mocha/auto_verify.rb +101 -34
- data/lib/mocha/expectation.rb +112 -3
- data/lib/mocha/mock.rb +9 -2
- data/lib/mocha/mock_methods.rb +21 -1
- data/lib/smart_test_case.rb +1 -1
- data/lib/smart_test_case/multiple_setup_and_teardown.rb +91 -89
- data/lib/stubba.rb +1 -1
- data/lib/stubba/object.rb +33 -8
- data/lib/stubba/setup_and_teardown.rb +19 -17
- data/test/all_tests.rb +0 -7
- data/test/mocha/auto_verify_test.rb +16 -1
- data/test/mocha/expectation_test.rb +8 -6
- data/test/mocha/mock_methods_test.rb +1 -1
- data/test/mocha/mock_test.rb +10 -0
- data/test/mocha_test_result_integration_test.rb +2 -2
- data/test/smart_test_case/multiple_setup_and_teardown_test.rb +11 -11
- data/test/stubba/setup_and_teardown_test.rb +3 -3
- data/test/stubba_integration_test.rb +7 -7
- data/test/stubba_test_result_integration_test.rb +2 -2
- metadata +3 -12
- data/TODO +0 -14
- data/lib/auto_mocha.rb +0 -2
- data/lib/auto_mocha/auto_mock.rb +0 -54
- data/lib/auto_mocha/mock_class.rb +0 -38
- data/test/auto_mocha/auto_mock_test.rb +0 -85
- data/test/auto_mocha/mock_class_test.rb +0 -179
- data/test/auto_mock_acceptance_test.rb +0 -35
data/README
CHANGED
@@ -1,164 +1,35 @@
|
|
1
1
|
= Mocha
|
2
2
|
|
3
|
-
Mocha is a library for mocking and stubbing within
|
3
|
+
Mocha is a library for mocking and stubbing within a TestCase[http://www.ruby-doc.org/core/classes/Test/Unit.html] using a syntax like that of JMock[http://www.jmock.org], and SchMock[http://rubyforge.org/projects/schmock].
|
4
4
|
|
5
|
-
|
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. This is a feature that is not currently offered by other Ruby[http://www.ruby-doc.org/] mocking libraries like FlexMock[http://onestepback.org/software/flexmock] and RSpec[http://rspec.rubyforge.org].
|
6
6
|
|
7
|
-
|
8
|
-
2. Stubba - allows mocking and stubbing of methods on real (non-mock) classes
|
9
|
-
3. AutoMocha - magically provides mocks in the place of undefined classes
|
10
|
-
4. SmartTestCase - allows addition of multiple setup and teardown methods for a Test::Unit::TestCase
|
7
|
+
Mocha provides a unified, simple and readable syntax for both traditional mocking and for mocking with non-mock objects.
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
== Provenance
|
15
|
-
|
16
|
-
Mocha and Stubba have been created by amalgamating a number of techniques developed by me (James[http:blog.floehopper.org]) and my Reevoo[http://www.reevoo.com] colleagues (Ben[http://www.reevoo.com/blogs/bengriffiths/], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com]) into a common syntax. They are both in use on real-world Rails[http://www.rubyonrails.org] projects. AutoMocha is more experimental and is at an earlier stage of development. SmartTestCase has been exrtacted from Mocha and Stubba to remove duplication and allow its use in isolation.
|
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.
|
17
10
|
|
18
11
|
== Download and Installation
|
19
12
|
|
20
|
-
|
13
|
+
Install the gem with the following command...
|
21
14
|
|
22
|
-
|
15
|
+
$ gem install mocha
|
23
16
|
|
24
|
-
|
17
|
+
Or install the Rails[http://www.rubyonrails.org] plugin...
|
25
18
|
|
26
19
|
$ script/plugin install svn://rubyforge.org/var/svn/mocha/trunk
|
27
20
|
|
28
|
-
|
29
|
-
|
30
|
-
Copyright Revieworld Ltd. 2006
|
31
|
-
|
32
|
-
You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt) or under the MIT license (see http://mocha.rubyforge.org/files/MIT-LICENSE.html).
|
21
|
+
Or download Mocha from here - http://rubyforge.org/projects/mocha
|
33
22
|
|
34
23
|
== Examples
|
35
24
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def initialize(dilithium)
|
43
|
-
@dilithium = dilithium
|
44
|
-
end
|
45
|
-
|
46
|
-
def go(warp_factor)
|
47
|
-
warp_factor.times { @dilithium.nuke(:anti_matter) }
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
require 'test/unit'
|
53
|
-
require 'rubygems'
|
54
|
-
require 'mocha'
|
55
|
-
|
56
|
-
class EnterpriseTest < Test::Unit::TestCase
|
57
|
-
|
58
|
-
def test_should_boldly_go
|
59
|
-
dilithium = mock()
|
60
|
-
dilithium.expects(:nuke).with(:anti_matter).at_least_once # auto-verified at end of test
|
61
|
-
enterprise = Enterprise.new(dilithium)
|
62
|
-
enterprise.go(2)
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
=== Stubba Example
|
68
|
-
|
69
|
-
class Order
|
70
|
-
|
71
|
-
attr_accessor :shipped_on
|
72
|
-
|
73
|
-
def total_cost
|
74
|
-
line_items.inject(0) { |total, line_item| total + line_item.price } + shipping_cost
|
75
|
-
end
|
76
|
-
|
77
|
-
def total_weight
|
78
|
-
line_items.inject(0) { |total, line_item| total + line_item.weight }
|
79
|
-
end
|
80
|
-
|
81
|
-
def shipping_cost
|
82
|
-
total_weight * 5 + 10
|
83
|
-
end
|
84
|
-
|
85
|
-
class << self
|
25
|
+
* Quick Start - {Usage Examples}[link:examples/misc.html]
|
26
|
+
* Traditional mocking - {Star Trek Example}[link:examples/mocha.html]
|
27
|
+
* Setting expectations on real classes - {Order Example}[link:examples/stubba.html]
|
28
|
+
* More examples on {Floehopper's Blog}[http://blog.floehopper.org]
|
29
|
+
* {Mailing List Archives}[http://rubyforge.org/pipermail/mocha-developer/]
|
86
30
|
|
87
|
-
|
88
|
-
# Database.connection.execute('select * from orders...
|
89
|
-
end
|
90
|
-
|
91
|
-
def number_shipped_since(date)
|
92
|
-
find_all.select { |order| order.shipped_on > date }.size
|
93
|
-
end
|
94
|
-
|
95
|
-
def unshipped_value
|
96
|
-
find_all.inject(0) { |total, order| order.shipped_on ? total : total + order.total_cost }
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
require 'test/unit'
|
104
|
-
require 'rubygems'
|
105
|
-
require 'stubba'
|
106
|
-
|
107
|
-
class OrderTest < Test::Unit::TestCase
|
108
|
-
|
109
|
-
# illustrates stubbing instance method
|
110
|
-
def test_should_calculate_shipping_cost_based_on_total_weight
|
111
|
-
order = Order.new
|
112
|
-
order.stubs(:total_weight).returns(10)
|
113
|
-
assert_equal 60, order.shipping_cost
|
114
|
-
end
|
115
|
-
|
116
|
-
# illustrates stubbing class method
|
117
|
-
def test_should_count_number_of_orders_shipped_after_specified_date
|
118
|
-
now = Time.now; week_in_secs = 7 * 24 * 60 * 60
|
119
|
-
order_1 = Order.new; order_1.shipped_on = now - 1 * week_in_secs
|
120
|
-
order_2 = Order.new; order_2.shipped_on = now - 3 * week_in_secs
|
121
|
-
Order.stubs(:find_all).returns([order_1, order_2])
|
122
|
-
assert_equal 1, Order.number_shipped_since(now - 2 * week_in_secs)
|
123
|
-
end
|
124
|
-
|
125
|
-
# illustrates stubbing instance method for all instances of a class
|
126
|
-
def test_should_calculate_value_of_unshipped_orders
|
127
|
-
Order.stubs(:find_all).returns([Order.new, Order.new, Order.new])
|
128
|
-
Order.any_instance.stubs(:shipped_on).returns(nil)
|
129
|
-
Order.any_instance.stubs(:total_cost).returns(10)
|
130
|
-
assert_equal 30, Order.unshipped_value
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
|
135
|
-
=== AutoMocha Example
|
136
|
-
|
137
|
-
class Article
|
138
|
-
|
139
|
-
attr_reader :id
|
140
|
-
|
141
|
-
def accepted_comments
|
142
|
-
Comment.find_all_by_article_id(self.id).select { |comment| comment.accepted? }
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
require 'rubygems'
|
148
|
-
require 'auto_mocha'
|
149
|
-
require 'test/unit'
|
150
|
-
|
151
|
-
class OrderTest < Test::Unit::TestCase
|
152
|
-
|
153
|
-
# illustrates stubbing of previously undefined class Comment
|
154
|
-
def test_should_return_accepted_comments_for_this_article
|
155
|
-
unaccepted_comment = stub(:accepted? => false)
|
156
|
-
accepted_comment = stub(:accepted? => true)
|
157
|
-
comments = [unaccepted_comment, accepted_comment]
|
158
|
-
Comment.stubs(:find_all_by_article_id).returns(comments)
|
159
|
-
article = Article.new
|
160
|
-
assert_equal [accepted_comment], article.accepted_comments
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
31
|
+
== License
|
164
32
|
|
33
|
+
Copyright Revieworld Ltd. 2006
|
34
|
+
|
35
|
+
You may use, copy and redistribute this library under the same terms as {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the {MIT license}[http://mocha.rubyforge.org/files/MIT-LICENSE.html].
|
data/Rakefile
CHANGED
@@ -3,6 +3,10 @@ require 'rake/rdoctask'
|
|
3
3
|
require 'rake/gempackagetask'
|
4
4
|
require 'rake/contrib/sshpublisher'
|
5
5
|
|
6
|
+
module Mocha
|
7
|
+
VERSION = "0.3.2"
|
8
|
+
end
|
9
|
+
|
6
10
|
desc "Default task is currently to run all tests"
|
7
11
|
task :default => :test_all
|
8
12
|
|
@@ -17,12 +21,14 @@ Rake::RDocTask.new do |task|
|
|
17
21
|
task.main = 'README'
|
18
22
|
task.title = 'Mocha'
|
19
23
|
task.rdoc_dir = 'doc'
|
24
|
+
task.template = "html_with_google_analytics"
|
20
25
|
task.options << "--line-numbers" << "--inline-source"
|
21
|
-
task.rdoc_files.include('README', 'RELEASE', 'COPYING', 'MIT-LICENSE', 'agiledox.txt', '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/stubba/object.rb')
|
22
27
|
end
|
28
|
+
task :rdoc => :examples
|
23
29
|
|
24
30
|
desc "Upload RDoc to RubyForge"
|
25
|
-
task :publish_rdoc => [:rdoc] do
|
31
|
+
task :publish_rdoc => [:rdoc, :examples] do
|
26
32
|
Rake::SshDirPublisher.new("jamesmead@rubyforge.org", "/var/www/gforge-projects/mocha", "doc").upload
|
27
33
|
end
|
28
34
|
|
@@ -42,16 +48,36 @@ file 'agiledox.txt' do
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
51
|
+
desc "Convert example ruby files to syntax-highlighted html"
|
52
|
+
task :examples do
|
53
|
+
require 'coderay'
|
54
|
+
mkdir_p 'doc/examples'
|
55
|
+
File.open('doc/examples/coderay.css', 'w') do |output|
|
56
|
+
output << CodeRay::Encoders[:html]::CSS.new.stylesheet
|
57
|
+
end
|
58
|
+
['mocha', 'stubba', 'misc'].each do |filename|
|
59
|
+
File.open("doc/examples/#{filename}.html", 'w') do |file|
|
60
|
+
file << "<html>"
|
61
|
+
file << "<head>"
|
62
|
+
file << %q(<link rel="stylesheet" media="screen" href="coderay.css" type="text/css">)
|
63
|
+
file << "</head>"
|
64
|
+
file << "<body>"
|
65
|
+
file << CodeRay.scan_file("examples/#{filename}.rb").html.div
|
66
|
+
file << "</body>"
|
67
|
+
file << "</html>"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
45
72
|
Gem::manage_gems
|
46
73
|
|
47
74
|
specification = Gem::Specification.new do |s|
|
48
75
|
s.name = "mocha"
|
49
76
|
s.summary = "Mocking and stubbing library"
|
50
|
-
s.version =
|
77
|
+
s.version = Mocha::VERSION
|
51
78
|
s.author = 'James Mead'
|
52
79
|
s.description = <<-EOF
|
53
80
|
Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes.
|
54
|
-
Includes auto-mocking which magically provides mocks for undefined classes, facilitating unit tests with no external dependencies.
|
55
81
|
EOF
|
56
82
|
s.email = 'mocha-developer@rubyforge.org'
|
57
83
|
s.homepage = 'http://mocha.rubyforge.org'
|
@@ -62,11 +88,39 @@ specification = Gem::Specification.new do |s|
|
|
62
88
|
s.rdoc_options << '--title' << 'Mocha' << '--main' << 'README' << '--line-numbers'
|
63
89
|
|
64
90
|
s.autorequire = 'mocha'
|
65
|
-
s.files = FileList['{lib,test}/**/*.rb', '[A-Z]*'].to_a
|
91
|
+
s.files = FileList['{lib,test}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a
|
66
92
|
s.test_file = "test/all_tests.rb"
|
67
93
|
end
|
68
94
|
|
69
95
|
Rake::GemPackageTask.new(specification) do |package|
|
70
96
|
package.need_zip = true
|
71
97
|
package.need_tar = true
|
72
|
-
end
|
98
|
+
end
|
99
|
+
|
100
|
+
task :verify_user do
|
101
|
+
raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
|
102
|
+
end
|
103
|
+
|
104
|
+
task :verify_password do
|
105
|
+
raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "Publish package files on RubyForge."
|
109
|
+
task :publish_packages => [:verify_user, :verify_password, :package] do
|
110
|
+
require 'meta_project'
|
111
|
+
require 'rake/contrib/xforge'
|
112
|
+
release_files = FileList[
|
113
|
+
"pkg/mocha-#{Mocha::VERSION}.gem",
|
114
|
+
"pkg/mocha-#{Mocha::VERSION}.tgz",
|
115
|
+
"pkg/mocha-#{Mocha::VERSION}.zip"
|
116
|
+
]
|
117
|
+
|
118
|
+
Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new('mocha')) do |release|
|
119
|
+
release.user_name = ENV['RUBYFORGE_USER']
|
120
|
+
release.password = ENV['RUBYFORGE_PASSWORD']
|
121
|
+
release.files = release_files.to_a
|
122
|
+
release.release_name = "Mocha #{Mocha::VERSION}"
|
123
|
+
release.release_changes = ''
|
124
|
+
release.release_notes = ''
|
125
|
+
end
|
126
|
+
end
|
data/lib/mocha.rb
CHANGED
data/lib/mocha/auto_verify.rb
CHANGED
@@ -1,46 +1,113 @@
|
|
1
1
|
require 'mocha/mock'
|
2
2
|
|
3
|
-
|
3
|
+
# Methods added to TestCase allowing creation of mock objects.
|
4
|
+
#
|
5
|
+
# Mocks created this way will have their expectations automatically verified at the end of the test.
|
6
|
+
#
|
7
|
+
# See Mocha::MockMethods for methods on mock objects.
|
8
|
+
module Mocha
|
9
|
+
module AutoVerify
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
|
11
|
+
def self.included(base) # :nodoc:
|
12
|
+
base.add_teardown_method(:teardown_mocks)
|
13
|
+
end
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
15
|
+
def mocks # :nodoc:
|
16
|
+
@mocks ||= []
|
17
|
+
end
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def mock(expectations = {})
|
18
|
-
build_mock_with_expectations(:expects, expectations)
|
19
|
-
end
|
19
|
+
def reset_mocks # :nodoc:
|
20
|
+
@mocks = nil
|
21
|
+
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
# :call-seq: mock(name) -> mock object
|
24
|
+
# mock(expected_methods = {}) -> mock object
|
25
|
+
# mock(name, expected_methods = {}) -> mock object
|
26
|
+
#
|
27
|
+
# Creates a mock object.
|
28
|
+
#
|
29
|
+
# +name+ is a +String+ identifier for the mock object.
|
30
|
+
#
|
31
|
+
# +expected_methods+ is a +Hash+ with expected method name symbols as keys and corresponding return values as values.
|
32
|
+
#
|
33
|
+
# Note that (contrary to expectations set up by #stub) these expectations <b>must</b> be fulfilled during the test.
|
34
|
+
# def test_product
|
35
|
+
# product = mock('ipod_product', :manufacturer => 'ipod', :price => 100)
|
36
|
+
# assert_equal 'ipod', product.manufacturer
|
37
|
+
# assert_equal 100, product.price
|
38
|
+
# # an error will be raised unless both Product#manufacturer and Product#price have been called
|
39
|
+
# end
|
40
|
+
def mock(*args)
|
41
|
+
name, expectations = name_and_expectations_from_args(args)
|
42
|
+
build_mock_with_expectations(:expects, expectations, name)
|
43
|
+
end
|
24
44
|
|
25
|
-
|
26
|
-
|
27
|
-
|
45
|
+
# :call-seq: stub(name) -> mock object
|
46
|
+
# stub(stubbed_methods = {}) -> mock object
|
47
|
+
# stub(name, stubbed_methods = {}) -> mock object
|
48
|
+
#
|
49
|
+
# Creates a mock object.
|
50
|
+
#
|
51
|
+
# +name+ is a +String+ identifier for the mock object.
|
52
|
+
#
|
53
|
+
# +stubbed_methods+ is a +Hash+ with stubbed method name symbols as keys and corresponding return values as values.
|
54
|
+
#
|
55
|
+
# Note that (contrary to expectations set up by #mock) these expectations <b>need not</b> be fulfilled during the test.
|
56
|
+
# def test_product
|
57
|
+
# product = stub('ipod_product', :manufacturer => 'ipod', :price => 100)
|
58
|
+
# assert_equal 'ipod', product.manufacturer
|
59
|
+
# assert_equal 100, product.price
|
60
|
+
# # an error will not be raised even if Product#manufacturer and Product#price have not been called
|
61
|
+
# end
|
62
|
+
def stub(*args)
|
63
|
+
name, expectations = name_and_expectations_from_args(args)
|
64
|
+
build_mock_with_expectations(:stubs, expectations, name)
|
65
|
+
end
|
66
|
+
|
67
|
+
# :call-seq: stub_everything(name) -> mock object
|
68
|
+
# stub_everything(stubbed_methods = {}) -> mock object
|
69
|
+
# stub_everything(name, stubbed_methods = {}) -> mock object
|
70
|
+
#
|
71
|
+
# Creates a mock object that accepts calls to any method.
|
72
|
+
#
|
73
|
+
# By default it will return +nil+ for any method call.
|
74
|
+
#
|
75
|
+
# +name+ and +stubbed_methods+ work in the same way as for #stub.
|
76
|
+
# def test_product
|
77
|
+
# product = stub_everything('ipod_product', :price => 100)
|
78
|
+
# assert_nil product.manufacturer
|
79
|
+
# assert_nil product.any_old_method
|
80
|
+
# assert_equal 100, product.price
|
81
|
+
# end
|
82
|
+
def stub_everything(*args)
|
83
|
+
name, expectations = name_and_expectations_from_args(args)
|
84
|
+
build_mock_with_expectations(:stub_everything, expectations, name)
|
85
|
+
end
|
28
86
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
87
|
+
def teardown_mocks # :nodoc:
|
88
|
+
mocks.each { |mock| mock.verify { add_assertion } }
|
89
|
+
reset_mocks
|
90
|
+
end
|
33
91
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
92
|
+
def build_mock_with_expectations(expectation_type = :expects, expectations = {}, name = nil) # :nodoc:
|
93
|
+
stub_everything = (expectation_type == :stub_everything)
|
94
|
+
expectation_type = :stubs if expectation_type == :stub_everything
|
95
|
+
mock = Mocha::Mock.new(stub_everything, name)
|
96
|
+
expectations.each do |method, result|
|
97
|
+
mock.send(expectation_type, method).returns(result)
|
98
|
+
end
|
99
|
+
mocks << mock
|
100
|
+
mock
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def name_and_expectations_from_args(args) # :nodoc:
|
106
|
+
name = args.first.is_a?(String) ? args.delete_at(0) : nil
|
107
|
+
expectations = args.first || {}
|
108
|
+
[name, expectations]
|
40
109
|
end
|
41
|
-
|
42
|
-
mock
|
110
|
+
|
43
111
|
end
|
44
112
|
|
45
|
-
end
|
46
|
-
|
113
|
+
end
|
data/lib/mocha/expectation.rb
CHANGED
@@ -2,8 +2,11 @@ require 'mocha/infinite_range'
|
|
2
2
|
require 'mocha/pretty_parameters'
|
3
3
|
|
4
4
|
module Mocha
|
5
|
+
# Methods on expectations returned from Mocha::MockMethods#expects and Mocha::MockMethods#stubs
|
5
6
|
class Expectation
|
6
7
|
|
8
|
+
# :stopdoc:
|
9
|
+
|
7
10
|
class InvalidExpectation < Exception; end
|
8
11
|
|
9
12
|
class AlwaysEqual
|
@@ -37,47 +40,146 @@ module Mocha
|
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
43
|
+
# :startdoc:
|
44
|
+
|
45
|
+
# :call-seq: times(range) -> expectation
|
46
|
+
#
|
47
|
+
# Modifies expectation so that the number of calls to the expected method must be within a specific +range+.
|
48
|
+
#
|
49
|
+
# +range+ can be specified as an exact integer or as a range of integers
|
50
|
+
# object = mock()
|
51
|
+
# object.expects(:expected_method).times(3)
|
52
|
+
# 3.times { object.expected_method } # => verify succeeds
|
53
|
+
#
|
54
|
+
# object = mock()
|
55
|
+
# object.expects(:expected_method).times(3)
|
56
|
+
# 2.times { object.expected_method } # => verify fails
|
57
|
+
#
|
58
|
+
# object = mock()
|
59
|
+
# object.expects(:expected_method).times(2..4)
|
60
|
+
# 3.times { object.expected_method } # => verify succeeds
|
61
|
+
#
|
62
|
+
# object = mock()
|
63
|
+
# object.expects(:expected_method).times(2..4)
|
64
|
+
# object.expected_method # => verify fails
|
40
65
|
def times(range)
|
41
66
|
@count = range
|
42
67
|
self
|
43
68
|
end
|
44
69
|
|
70
|
+
# :call-seq: never -> expectation
|
71
|
+
#
|
72
|
+
# Modifies expectation so that the expected method must never be called.
|
73
|
+
# object = mock()
|
74
|
+
# object.expects(:expected_method).never
|
75
|
+
# object.expected_method # => verify fails
|
76
|
+
#
|
77
|
+
# object = mock()
|
78
|
+
# object.expects(:expected_method).never
|
79
|
+
# object.expected_method # => verify succeeds
|
45
80
|
def never
|
46
81
|
times(0)
|
47
82
|
end
|
48
83
|
|
84
|
+
# :call-seq: at_least(minimum) -> expectation
|
85
|
+
#
|
86
|
+
# Modifies expectation so that the expected method must be called at least a +minimum+ number of times.
|
87
|
+
# object = mock()
|
88
|
+
# object.expects(:expected_method).at_least(2)
|
89
|
+
# 3.times { object.expected_method } # => verify succeeds
|
90
|
+
#
|
91
|
+
# object = mock()
|
92
|
+
# object.expects(:expected_method).at_least(2)
|
93
|
+
# object.expected_method # => verify fails
|
49
94
|
def at_least(minimum)
|
50
95
|
times(Range.at_least(minimum))
|
51
96
|
self
|
52
97
|
end
|
53
98
|
|
99
|
+
# :call-seq: at_least_once() -> expectation
|
100
|
+
#
|
101
|
+
# Modifies expectation so that the expected method must be called at least once.
|
102
|
+
# object = mock()
|
103
|
+
# object.expects(:expected_method).at_least_once
|
104
|
+
# object.expected_method # => verify succeeds
|
105
|
+
#
|
106
|
+
# object = mock()
|
107
|
+
# object.expects(:expected_method).at_least_once
|
108
|
+
# # => verify fails
|
54
109
|
def at_least_once()
|
55
110
|
at_least(1)
|
56
111
|
self
|
57
112
|
end
|
58
113
|
|
114
|
+
# :call-seq: with(*arguments, ¶meter_block) -> expectation
|
115
|
+
#
|
116
|
+
# Modifies expectation so that the expected method must be called with specified +arguments+.
|
117
|
+
# object = mock()
|
118
|
+
# object.expects(:expected_method).with(:param1, :param2)
|
119
|
+
# object.expected_method(:param1, :param2) # => verify succeeds
|
120
|
+
#
|
121
|
+
# object = mock()
|
122
|
+
# object.expects(:expected_method).with(:param1, :param2)
|
123
|
+
# object.expected_method(:param3) # => verify fails
|
124
|
+
# If a +parameter_block+ is given, the block is called with the parameters passed to the expected method.
|
125
|
+
# The expectation is matched if the block evaluates to +true+.
|
126
|
+
# object = mock()
|
127
|
+
# object.expects(:expected_method).with() { |value| value % 4 == 0 }
|
128
|
+
# object.expected_method(16) # => verify succeeds
|
129
|
+
#
|
130
|
+
# object = mock()
|
131
|
+
# object.expects(:expected_method).with() { |value| value % 4 == 0 }
|
132
|
+
# object.expected_method(17) # => verify fails
|
59
133
|
def with(*arguments, ¶meter_block)
|
60
134
|
@parameters, @parameter_block = arguments, parameter_block
|
61
135
|
class << @parameters; def to_s; join(', '); end; end
|
62
136
|
self
|
63
137
|
end
|
64
138
|
|
139
|
+
# :call-seq: yields(*parameters) -> expectation
|
140
|
+
#
|
141
|
+
# Modifies expectation so that when the expected method is called, it yields with the specified +parameters+.
|
142
|
+
# object = mock()
|
143
|
+
# object.expects(:expected_method).yields('result')
|
144
|
+
# yielded_value = nil
|
145
|
+
# object.expected_method { |value| yielded_value = value }
|
146
|
+
# yielded_value # => 'result'
|
65
147
|
def yields(*parameters)
|
66
148
|
@yield = true
|
67
149
|
@parameters_to_yield = parameters
|
68
150
|
self
|
69
151
|
end
|
70
152
|
|
153
|
+
# :call-seq: returns(value) -> expectation
|
154
|
+
#
|
155
|
+
# Modifies expectation so that when the expected method is called, it returns the specified +value+.
|
156
|
+
# object = mock()
|
157
|
+
# object.expects(:expected_method).returns('result')
|
158
|
+
# object.expected_method # => 'result'
|
159
|
+
# If +value+ is a Proc, then expected method will return result of calling Proc.
|
160
|
+
# object = mock()
|
161
|
+
# results = [111, 222]
|
162
|
+
# object.stubs(:expected_method).returns(lambda { results.shift })
|
163
|
+
# object.expected_method # => 111
|
164
|
+
# object.expected_method # => 222
|
71
165
|
def returns(value)
|
72
166
|
@return_value = value
|
73
167
|
self
|
74
168
|
end
|
75
169
|
|
170
|
+
# :call-seq: raises(exception = RuntimeError, message = nil) -> expectation
|
171
|
+
#
|
172
|
+
# Modifies expectation so that when the expected method is called, it raises the specified +exception+ with the specified +message+.
|
173
|
+
# object = mock()
|
174
|
+
# object.expects(:expected_method).raises(Exception, 'message')
|
175
|
+
# object.expected_method # => raises exception of class Exception and with message 'message'
|
76
176
|
def raises(exception = RuntimeError, message = nil)
|
77
177
|
@return_value = lambda{ raise exception, message }
|
78
178
|
self
|
79
179
|
end
|
80
180
|
|
181
|
+
# :stopdoc:
|
182
|
+
|
81
183
|
def invoke
|
82
184
|
@invoked += 1
|
83
185
|
yield(*@parameters_to_yield) if yield? and block_given?
|
@@ -99,8 +201,12 @@ module Mocha
|
|
99
201
|
":#{@method_name}(#{params.pretty})"
|
100
202
|
end
|
101
203
|
|
204
|
+
# :startdoc:
|
205
|
+
|
102
206
|
end
|
103
207
|
|
208
|
+
# :stopdoc:
|
209
|
+
|
104
210
|
class Stub < Expectation
|
105
211
|
|
106
212
|
def verify
|
@@ -111,14 +217,14 @@ module Mocha
|
|
111
217
|
|
112
218
|
class MissingExpectation < Expectation
|
113
219
|
|
114
|
-
def initialize(method_name, expectations = [])
|
220
|
+
def initialize(method_name, mock, expectations = [])
|
115
221
|
super(method_name)
|
116
|
-
@expectations = expectations
|
222
|
+
@mock, @expectations = mock, expectations
|
117
223
|
@invoked = true
|
118
224
|
end
|
119
225
|
|
120
226
|
def verify
|
121
|
-
msg = "Unexpected message #{message}"
|
227
|
+
msg = "Unexpected message #{message} sent to #{@mock.mocha_inspect}"
|
122
228
|
msg << "\nSimilar expectations #{similar_expectations.collect { |expectation| expectation.message }.join("\n") }" unless similar_expectations.empty?
|
123
229
|
raise Test::Unit::AssertionFailedError, msg if @invoked
|
124
230
|
end
|
@@ -128,4 +234,7 @@ module Mocha
|
|
128
234
|
end
|
129
235
|
|
130
236
|
end
|
237
|
+
|
238
|
+
# :startdoc:
|
239
|
+
|
131
240
|
end
|