redinger-rr 0.10.3

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.
Files changed (133) hide show
  1. data/CHANGES +221 -0
  2. data/README.rdoc +343 -0
  3. data/Rakefile +88 -0
  4. data/VERSION.yml +4 -0
  5. data/lib/rr.rb +88 -0
  6. data/lib/rr/adapters/rr_methods.rb +122 -0
  7. data/lib/rr/adapters/rspec.rb +59 -0
  8. data/lib/rr/adapters/test_unit.rb +29 -0
  9. data/lib/rr/double.rb +152 -0
  10. data/lib/rr/double_definitions/child_double_definition_creator.rb +27 -0
  11. data/lib/rr/double_definitions/double_definition.rb +348 -0
  12. data/lib/rr/double_definitions/double_definition_creator.rb +167 -0
  13. data/lib/rr/double_definitions/double_definition_creator_proxy.rb +37 -0
  14. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
  15. data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
  16. data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
  17. data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
  18. data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
  19. data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +50 -0
  20. data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
  21. data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
  22. data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
  23. data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
  24. data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
  25. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
  26. data/lib/rr/double_injection.rb +180 -0
  27. data/lib/rr/double_matches.rb +51 -0
  28. data/lib/rr/errors/argument_equality_error.rb +6 -0
  29. data/lib/rr/errors/double_definition_error.rb +6 -0
  30. data/lib/rr/errors/double_not_found_error.rb +6 -0
  31. data/lib/rr/errors/double_order_error.rb +6 -0
  32. data/lib/rr/errors/rr_error.rb +20 -0
  33. data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
  34. data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
  35. data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
  36. data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
  37. data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
  38. data/lib/rr/errors/times_called_error.rb +6 -0
  39. data/lib/rr/expectations/any_argument_expectation.rb +21 -0
  40. data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
  41. data/lib/rr/expectations/times_called_expectation.rb +57 -0
  42. data/lib/rr/hash_with_object_id_key.rb +44 -0
  43. data/lib/rr/method_dispatches/base_method_dispatch.rb +108 -0
  44. data/lib/rr/method_dispatches/method_dispatch.rb +61 -0
  45. data/lib/rr/method_dispatches/method_missing_dispatch.rb +49 -0
  46. data/lib/rr/proc_from_block.rb +7 -0
  47. data/lib/rr/recorded_calls.rb +103 -0
  48. data/lib/rr/space.rb +123 -0
  49. data/lib/rr/spy_verification.rb +48 -0
  50. data/lib/rr/spy_verification_proxy.rb +18 -0
  51. data/lib/rr/times_called_matchers/any_times_matcher.rb +18 -0
  52. data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
  53. data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
  54. data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
  55. data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
  56. data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
  57. data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
  58. data/lib/rr/times_called_matchers/terminal.rb +20 -0
  59. data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
  60. data/lib/rr/wildcard_matchers.rb +158 -0
  61. data/lib/rr/wildcard_matchers/anything.rb +18 -0
  62. data/lib/rr/wildcard_matchers/boolean.rb +23 -0
  63. data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
  64. data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
  65. data/lib/rr/wildcard_matchers/is_a.rb +25 -0
  66. data/lib/rr/wildcard_matchers/numeric.rb +13 -0
  67. data/lib/rr/wildcard_matchers/range.rb +7 -0
  68. data/lib/rr/wildcard_matchers/regexp.rb +7 -0
  69. data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
  70. data/spec/core_spec_suite.rb +19 -0
  71. data/spec/environment_fixture_setup.rb +7 -0
  72. data/spec/high_level_spec.rb +398 -0
  73. data/spec/proc_from_block_spec.rb +14 -0
  74. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
  75. data/spec/rr/adapters/rr_methods_creator_spec.rb +149 -0
  76. data/spec/rr/adapters/rr_methods_space_spec.rb +115 -0
  77. data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
  78. data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +17 -0
  79. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
  80. data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +155 -0
  81. data/spec/rr/double_definitions/double_definition_creator_spec.rb +502 -0
  82. data/spec/rr/double_definitions/double_definition_spec.rb +1165 -0
  83. data/spec/rr/double_injection/double_injection_spec.rb +339 -0
  84. data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
  85. data/spec/rr/double_spec.rb +352 -0
  86. data/spec/rr/errors/rr_error_spec.rb +67 -0
  87. data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
  88. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  89. data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
  90. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
  91. data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  92. data/spec/rr/expectations/hash_including_spec.rb +17 -0
  93. data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
  94. data/spec/rr/expectations/satisfy_spec.rb +14 -0
  95. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +46 -0
  96. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +69 -0
  97. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
  98. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +23 -0
  99. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +104 -0
  100. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +81 -0
  101. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +83 -0
  102. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +38 -0
  103. data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
  104. data/spec/rr/rspec/rspec_adapter_spec.rb +66 -0
  105. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +31 -0
  106. data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
  107. data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
  108. data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
  109. data/spec/rr/space/space_spec.rb +550 -0
  110. data/spec/rr/test_unit/test_helper.rb +7 -0
  111. data/spec/rr/test_unit/test_unit_backtrace_test.rb +36 -0
  112. data/spec/rr/test_unit/test_unit_integration_test.rb +57 -0
  113. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
  114. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
  115. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
  116. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
  117. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
  118. data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
  119. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
  120. data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
  121. data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
  122. data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
  123. data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
  124. data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
  125. data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
  126. data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
  127. data/spec/rr_spec.rb +28 -0
  128. data/spec/rspec_spec_suite.rb +17 -0
  129. data/spec/spec_helper.rb +109 -0
  130. data/spec/spec_suite.rb +31 -0
  131. data/spec/spy_verification_spec.rb +129 -0
  132. data/spec/test_unit_spec_suite.rb +21 -0
  133. metadata +193 -0
data/CHANGES ADDED
@@ -0,0 +1,221 @@
1
+ - Handle lazily defined methods (where respond_to? returns true yet the method is not yet defined and the first call to method_missing defines the method). This pattern is used in ActiveRecord and ActionMailer.
2
+ - Fixed warning about aliasing #instance_exec in jruby. http://github.com/btakita/rr/issues#issue/9 (Patch by Nathan Sobo)
3
+
4
+ 0.10.2
5
+ - RR properly proxies subjects with private methods [http://github.com/btakita/rr/issues/#issue/7]. Identified by Matthew O'Connor.
6
+
7
+ 0.10.1
8
+ - Fixed issue with DoubleInjection not invoking methods that are lazily created [http://github.com/btakita/rr/issues/#issue/4]. Identified by davidlee (http://github.com/davidlee)
9
+ - Fixed issue with mock.proxy and returns [http://github.com/btakita/rr/issues/#issue/2]. Identified by trogdoro (http://github.com/trogdoro)
10
+
11
+ * 0.10.0
12
+ - Method is no longer invoked if respond_to? returns false. This was in place to support ActiveRecord association proxies, and is no longer needed.
13
+
14
+ * 0.9.0
15
+ - instance_of Doubles now apply to methods invoked in the subject's #initialize method.
16
+
17
+ * 0.8.1
18
+ - Fixed exception where the Subject uses method delegation via method_missing (e.g. certain ActiveRecord AssociationProxy methods)
19
+
20
+ * 0.8.0
21
+ - Fixed compatability issues with Ruby 1.9
22
+ - Aliased any_number_of_times with any_times
23
+ - Better error messages for have_received and assert_received matchers (Patch by Joe Ferris)
24
+ - Better documentation on RR wilcard matchers (Patch by Phil Arnowsky)
25
+
26
+ * 0.7.1
27
+ - Performance improvements
28
+
29
+ * 0.7.0
30
+ - Added spies (Patchs by Joe Ferris, Michael Niessner & Mike Mangino)
31
+ - Added strongly typed reimplementation doubles (Patch by Michael Niessner)
32
+
33
+ * 0.6.2
34
+ - Fixed DoubleDefinition chaining edge cases
35
+
36
+ * 0.6.1
37
+ - DoubleDefinitionCreatorProxy definition eval block is instance_evaled when the arity is not 1. When the arity is 1, the block is yielded with the DoubleDefinitionCreatorProxy passed in.
38
+
39
+ * 0.6.0
40
+ - Friendlier DoubleNotFound error message
41
+ - Implemented Double strategy creation methods (#mock, #stub, #proxy, #instance_of, and ! equivalents) on DoubleDefinition
42
+ - Implemented hash_including matcher (Patch by Matthew O'Conner)
43
+ - Implemented satisfy matcher (Patch by Matthew O'Conner)
44
+ - Implemented DoubleDefinitionCreator#mock!, #stub!, and #dont_allow!
45
+ - Modified api to method chain Doubles
46
+ - Fix conflict with Mocha overriding Object#verify
47
+
48
+ * 0.5.0
49
+ - Method chaining Doubles (Patch by Nick Kallen)
50
+ - Chained ordered expectations (Patch by Nick Kallen)
51
+ - Space#verify_doubles can take one or more objects with DoubleInjections to be verified
52
+
53
+ * 0.4.10
54
+ - DoubleDefinitionCreatorProxy does not undef #object_id
55
+ - Fixed rdoc pointer to README
56
+
57
+ * 0.4.9
58
+ - Proxying from RR module to RR::Space.instance
59
+
60
+ * 0.4.8
61
+ - Fixed issue with Hash arguments
62
+
63
+ * 0.4.7
64
+ - Improved error message
65
+
66
+ * 0.4.6
67
+ - Added Double#verbose and Double#verbose?
68
+
69
+ * 0.4.5
70
+ - Fixed doubles for == and #eql? methods
71
+
72
+ * 0.4.4
73
+ - Doc improvements
74
+ - Methods that are not alphabetic, such as ==, can be doubles
75
+
76
+ * 0.4.3
77
+ - Doc improvements
78
+ - Cleanup
79
+ - Finished renaming scenario to double
80
+
81
+ * 0.4.2
82
+ - Renamed DoubleInsertion to DoubleInjection to be consistent with Mocha terminology
83
+
84
+ * 0.4.1
85
+ - Fixed backward compatability issues with rspec
86
+ - Renamed Space#verify_double_insertions to #verify_doubles
87
+
88
+ * 0.4.0
89
+ - Documentation improvements
90
+ - Renamed Double to DoubleInsertion
91
+ - Renamed Scenario to Double
92
+
93
+ * 0.3.11
94
+ - Fixed [#13724] Mock Proxy on Active Record Association proxies causes error
95
+
96
+ * 0.3.10
97
+ - Fixed [#13139] Blocks added to proxy sets the return_value and not the after_call callback
98
+
99
+ * 0.3.9
100
+ - Alias probe to proxy
101
+
102
+ * 0.3.8
103
+ - Implemented [#13009] Better error mesage from TimesCalledMatcher
104
+
105
+ * 0.3.7
106
+ - Fixed [#12928] Reset doubles fails on Rails association proxies
107
+
108
+ * 0.3.6
109
+ - Fixed [#12765] Issues with ObjectSpace._id2ref
110
+
111
+ * 0.3.5
112
+ - trim_backtrace is only set for Test::Unit
113
+
114
+ * 0.3.4
115
+ - Implemented instance_of
116
+
117
+ * 0.3.3
118
+ - Fixed [#12495] Error Probing method_missing interaction
119
+
120
+ * 0.3.2
121
+ - Fixed [#12486] ScenarioMethodProxy when Kernel passed into instance methods
122
+
123
+ * 0.3.1
124
+ - Automatically require Test::Unit and Rspec adapters
125
+
126
+ * 0.3.0
127
+ - ScenarioCreator strategy method chaining
128
+ - Removed mock_probe
129
+ - Removed stub_probe
130
+
131
+ * 0.2.5
132
+ - mock takes method_name argument
133
+ - stub takes method_name argument
134
+ - mock_probe takes method_name argument
135
+ - stub_probe takes method_name argument
136
+ - probe takes method_name argument
137
+ - dont_allow takes method_name argument
138
+ - do_not_allow takes method_name argument
139
+
140
+ * 0.2.4
141
+ - Space#doubles key is now the object id
142
+ - Fixed [#12402] Stubbing return value of probes fails after calling the stubbed method two times
143
+
144
+ * 0.2.3
145
+ - Added RRMethods#rr_verify and RRMethods#rr_reset
146
+
147
+ * 0.2.2
148
+ - Fixed "singleton method bound for a different object"
149
+ - Doing Method aliasing again to store original method
150
+
151
+ * 0.2.1
152
+ - Added mock_probe
153
+ - Added stub_probe
154
+ - Probe returns the return value of the passed in block, instead of ignoring its return value
155
+ - Scenario#after_call returns the return value of the passed in block
156
+ - Not using method aliasing to store original method
157
+ - Renamed DoubleMethods to RRMethods
158
+ - Added RRMethods#mock_probe
159
+
160
+ * 0.1.15
161
+ - Fixed [#12333] Rebinding original_methods causes blocks not to work
162
+
163
+ * 0.1.14
164
+ - Introduced concept of Terminal and NonTerminal TimesCalledMatchers
165
+ - Doubles that can be called many times can be replaced
166
+ - Terminal Scenarios are called before NonTerminal Scenarios
167
+ - Error message tweaking
168
+ - Raise error when making a Scenarios with NonTerminal TimesMatcher Ordered
169
+
170
+ * 0.1.13
171
+ - Fixed [#12290] Scenario#returns with false causes a return value of nil
172
+
173
+ * 0.1.12
174
+ - Fixed bug where Creators methods are not removed when methods are defined on Object
175
+ - Fixed [#12289] Creators methods are not removed in Rails environment
176
+
177
+ * 0.1.11
178
+ - Fixed [#12287] AtLeastMatcher does not cause Scenario to be called
179
+
180
+ * 0.1.10
181
+ - Fixed [#12286] AnyArgumentExpectation#expected_arguments not implemented
182
+
183
+ * 0.1.9
184
+ - Added DoubleMethods#any_times
185
+ - Added Scenario#any_number_of_times
186
+
187
+ * 0.1.8
188
+ - TimesCalledError Message Formatted to be on multiple lines
189
+ - ScenarioNotFoundError Message includes all Scenarios for the Double
190
+ - ScenarioOrderError shows list of remaining ordered scenarios
191
+
192
+ * 0.1.7
193
+ - Fixed [#12194] Double#reset_doubles are not clearing Ordered Scenarios bug
194
+ - Added Space#reset
195
+ - Space#reset_doubles and Space#reset_ordered_scenarios is now protected
196
+ - Added Scenario#at_least
197
+ - Added Scenario#at_most
198
+
199
+ * 0.1.6
200
+ - [#12120] probe allows a the return value to be intercepted
201
+
202
+ * 0.1.5
203
+ - TimesCalledExpectation says how many times were called and how many times called were expected on error
204
+
205
+ * 0.1.4
206
+ - TimesCalledError prints the backtrace to where the Scenario was defined when being verified
207
+ - Error message includes method name when Scenario is not found
208
+
209
+ * 0.1.3
210
+ - Fixed issue where Double#placeholder_name issues when Double method name has a ! or ?
211
+
212
+ * 0.1.2
213
+ - Scenario#returns also accepts an argument
214
+ - Implemented Scenario#yields
215
+
216
+ * 0.1.1
217
+ - Trim the backtrace for Rspec and Test::Unit
218
+ - Rspec and Test::Unit integration fixes
219
+
220
+ * 0.1.0
221
+ - Initial Release
@@ -0,0 +1,343 @@
1
+ = RR
2
+
3
+ RR (Double Ruby) is a test double framework that features a rich
4
+ selection of double techniques and a terse syntax.
5
+
6
+ == More Information
7
+ === Mailing Lists
8
+ * double-ruby-users@rubyforge.org
9
+ * double-ruby-devel@rubyforge.org
10
+
11
+ === Websites
12
+ * http://rubyforge.org/projects/double-ruby
13
+ * http://github.com/btakita/rr
14
+
15
+ == What is a Test Double?
16
+ A Test Double is a generalization of something that replaces a real
17
+ object to make it easier to test another object. Its like a stunt
18
+ double for tests. The following are test doubles:
19
+ * Mocks
20
+ * Stubs
21
+ * Fakes
22
+ * Spies
23
+ * Proxies
24
+ http://xunitpatterns.com/Test%20Double.html
25
+
26
+ Currently RR implements mocks, stubs, proxies, and spies. Fakes usually require custom code, so it is beyond the scope of RR.
27
+
28
+ == Using RR
29
+ === test/unit
30
+ class Test::Unit::TestCase
31
+ include RR::Adapters::TestUnit
32
+ end
33
+
34
+ === rspec
35
+ Spec::Runner.configure do |config|
36
+ config.mock_with :rr
37
+ # or if that doesn't work due to a version incompatibility
38
+ # config.mock_with RR::Adapters::Rspec
39
+ end
40
+
41
+ == standalone
42
+ extend RR::Adapters::RRMethods
43
+ mock(object).method_name {:return_value}
44
+
45
+ object.method_name # Returns :return_value
46
+
47
+ RR.verify # Verifies the Double expectations are satisfied
48
+
49
+ == Syntax between RR and other double/mock frameworks
50
+ === Terse Syntax
51
+ One of the goals of RR is to make doubles more scannable.
52
+ This is accomplished by making the double declaration look as much as the actual method invocation as possible.
53
+ Here is RR compared to other mock frameworks:
54
+
55
+ flexmock(User).should_receive(:find).with('42').and_return(jane) # Flexmock
56
+ User.should_receive(:find).with('42').and_return(jane) # Rspec
57
+ User.expects(:find).with('42').returns {jane} # Mocha
58
+ User.should_receive(:find).with('42') {jane} # Rspec using return value blocks
59
+ mock(User).find('42') {jane} # RR
60
+
61
+ === Double Injections (a.k.a Partial Mocking)
62
+ RR utilizes a technique known as "double injection".
63
+
64
+ my_object = MyClass.new
65
+ mock(my_object).hello
66
+
67
+ Compare this with doing a mock in mocha:
68
+ my_mocked_object = mock()
69
+ my_mocked_object.expects(:hello)
70
+
71
+ == Pure Mock objects
72
+ If you wish to use objects for the sole purpose of being a mock, you can
73
+ do so by creating an empty object.
74
+ mock(my_mock_object = Object.new).hello
75
+
76
+ or by using mock!
77
+ my_mock_object = mock!.hello.subject # Mocks the #hello method and retrieves that object via the #subject method
78
+
79
+ === No should_receive or expects method
80
+ RR uses method_missing to set your method expectation. This means you do not
81
+ need to use a method such as should_receive or expects.
82
+
83
+ mock(my_object).hello # The hello method on my_object is mocked
84
+
85
+ Mocha:
86
+ my_object.expects(:hello) # expects sets the hello method expectation
87
+ Rspec mocks:
88
+ my_object.should_receive(:hello) # should_receive sets the hello method expectation
89
+
90
+ === with method call is not necessary
91
+ Since RR uses method_missing, it also makes using the #with method unnecessary in most circumstances
92
+ to set the argument expectations.
93
+
94
+ mock(my_object).hello('bob', 'jane')
95
+
96
+ Mocha:
97
+ my_object.expects(:hello).with('bob', 'jane')
98
+ Rspec mocks:
99
+ my_object.should_receive(:hello).with('bob', 'jane')
100
+
101
+ === using a block to set the return value
102
+ RR supports using a block to set the return value. RR also has the #returns method.
103
+ Both of the examples are equivalent.
104
+
105
+ mock(my_object).hello('bob', 'jane') {'Hello Bob and Jane'}
106
+ mock(my_object).hello('bob', 'jane').returns('Hello Bob and Jane')
107
+
108
+ Mocha:
109
+ my_object.expects(:hello).with('bob', 'jane').returns('Hello Bob and Jane')
110
+ Rspec mocks:
111
+ my_object.should_receive(:hello).with('bob', 'jane').and_return('Hello Bob and Jane')
112
+ my_object.should_receive(:hello).with('bob', 'jane') {'Hello Bob and Jane'} #rspec also supports blocks for the return value
113
+
114
+ == Using RR
115
+ To create a double on an object, you can use the following methods:
116
+ * mock or mock!
117
+ * stub or stub!
118
+ * dont_allow or dont_allow!
119
+ * proxy or proxy!
120
+ * instance_of or instance_of!
121
+
122
+ These methods are composable. mock, stub, and dont_allow can be used by themselves and
123
+ are mutually exclusive.
124
+ proxy and instance_of must be chained with mock or stub. You can also chain
125
+ proxy and instance_of together.
126
+
127
+ The ! (bang) version of these methods causes the subject object of the Double to be instantiated.
128
+
129
+ === mock
130
+ mock replaces the method on the object with an expectation and implementation.
131
+ The expectations are a mock will be called with certain arguments a certain
132
+ number of times (the default is once). You can also set the return value
133
+ of the method invocation.
134
+
135
+ See http://xunitpatterns.com/Mock%20Object.html
136
+
137
+ The following example sets an expectation that the view will receive a method
138
+ call to #render with the arguments {:partial => "user_info"} once.
139
+ When the method is called "Information" is returned.
140
+ view = controller.template
141
+ mock(view).render(:partial => "user_info") {"Information"}
142
+
143
+ === stub
144
+ stub replaces the method on the object with only an implementation. You
145
+ can still use arguments to differentiate which stub gets invoked.
146
+
147
+ See http://xunitpatterns.com/Test%20Stub.html
148
+
149
+ The following example makes the User.find method return jane when passed
150
+ '42' and returns bob when passed '99'. If another id is passed to User.find,
151
+ an exception is raised.
152
+ jane = User.new
153
+ bob = User.new
154
+ stub(User).find('42') {jane}
155
+ stub(User).find('99') {bob}
156
+ stub(User).find do |id|
157
+ raise "Unexpected id #{id.inspect} passed to me"
158
+ end
159
+
160
+ === dont_allow - aliased with do_not_allow, dont_call, and do_not_call
161
+ dont_allow sets an expectation on the Double that it will never be called.
162
+ If the Double is called, then a TimesCalledError is raised.
163
+ dont_allow(User).find('42')
164
+ User.find('42') # raises a TimesCalledError
165
+
166
+ === mock.proxy
167
+ mock.proxy replaces the method on the object with an expectation, implementation, and
168
+ also invokes the actual method. mock.proxy also intercepts the return value and
169
+ passes it into the return value block.
170
+
171
+ The following example makes sets an expectation that view.render({:partial => "right_navigation"})
172
+ gets called once and return the actual content of the rendered partial template.
173
+ A call to view.render({:partial => "user_info"}) will render the user_info
174
+ partial template and send the content into the block and is represented by the html variable.
175
+ An assertion is done on the html and "Different html" is returned.
176
+ view = controller.template
177
+ mock.proxy(view).render(:partial => "right_navigation")
178
+ mock.proxy(view).render(:partial => "user_info") do |html|
179
+ html.should include("John Doe")
180
+ "Different html"
181
+ end
182
+
183
+ You can also use mock.proxy to set expectations on the returned value. In
184
+ the following example, a call to User.find('5') does the normal ActiveRecord
185
+ implementation and passes the actual value, represented by the variable bob,
186
+ into the block. bob is then set with a mock.proxy for projects to return
187
+ only the first 3 projects. bob is also mocked with valid? to return false.
188
+ mock.proxy(User).find('5') do |bob|
189
+ mock.proxy(bob).projects do |projects|
190
+ projects[0..3]
191
+ end
192
+ mock(bob).valid? {false}
193
+ bob
194
+ end
195
+
196
+ === stub.proxy
197
+ Intercept the return value of a method call.
198
+ The following example verifies render partial will be called and
199
+ renders the partial.
200
+
201
+ view = controller.template
202
+ stub.proxy(view).render(:partial => "user_info") do |html|
203
+ html.should include("Joe Smith")
204
+ html
205
+ end
206
+
207
+ === instance_of
208
+ Put double scenarios on instances of a Class.
209
+
210
+ mock.instance_of(User).valid? {false}
211
+
212
+ === Spies
213
+
214
+ Adding a DoubleInjection to an Object + Method (done by stub, mock, or dont_allow) causes RR to record any method
215
+ invocations to the Object + method. Assertions can then be made on the recorded method calls.
216
+
217
+ ==== test/unit
218
+
219
+ subject = Object.new
220
+ stub(subject).foo
221
+ subject.foo(1)
222
+ assert_received(subject) {|subject| subject.foo(1)}
223
+ assert_received(subject) {|subject| subject.bar} # This fails
224
+
225
+ ==== rspec
226
+
227
+ subject = Object.new
228
+ stub(subject).foo
229
+ subject.foo(1)
230
+ subject.should have_received.foo(1)
231
+ subject.should have_received.bar # this fails
232
+
233
+ === Block Syntax
234
+ The block syntax has two modes
235
+ * A normal block mode with a DoubleDefinitionCreatorProxy argument
236
+
237
+ script = MyScript.new
238
+ mock(script) do |expect|
239
+ expect.system("cd #{RAILS_ENV}") {true}
240
+ expect.system("rake foo:bar") {true}
241
+ expect.system("rake baz") {true}
242
+ end
243
+
244
+ * An instance_eval mode where the DoubleDefinitionCreatorProxy is instance_evaled
245
+
246
+ script = MyScript.new
247
+ mock(script) do
248
+ system("cd #{RAILS_ENV}") {true}
249
+ system("rake foo:bar") {true}
250
+ system("rake baz") {true}
251
+ end
252
+
253
+ === Block Syntax with explicit DoubleDefinitionCreatorProxy argument
254
+
255
+
256
+ === Double Graphs
257
+ RR has a method-chaining api support for Double graphs. For example,
258
+ lets say you want an object to receive a method call to #foo, and have
259
+ the return value receive a method call to #bar.
260
+
261
+ In RR, you would do:
262
+ stub(object).foo.stub!.bar {:baz}
263
+ object.foo.bar # :baz
264
+ # or
265
+ stub(object).foo {stub!.bar {:baz}}
266
+ object.foo.bar # :baz
267
+ # or
268
+ bar = stub!.bar {:baz}
269
+ stub(object).foo {bar}
270
+ object.foo.bar # :baz
271
+
272
+ === Argument Wildcard matchers
273
+ ==== anything
274
+ mock(object).foobar(1, anything)
275
+ object.foobar(1, :my_symbol)
276
+
277
+ ==== is_a
278
+ mock(object).foobar(is_a(Time))
279
+ object.foobar(Time.now)
280
+
281
+ ==== numeric
282
+ mock(object).foobar(numeric)
283
+ object.foobar(99)
284
+
285
+ ==== boolean
286
+ mock(object).foobar(boolean)
287
+ object.foobar(false)
288
+
289
+ ==== duck_type
290
+ mock(object).foobar(duck_type(:walk, :talk))
291
+ arg = Object.new
292
+ def arg.walk; 'waddle'; end
293
+ def arg.talk; 'quack'; end
294
+ object.foobar(arg)
295
+
296
+ ==== Ranges
297
+ mock(object).foobar(1..10)
298
+ object.foobar(5)
299
+
300
+ ==== Regexps
301
+ mock(object).foobar(/on/)
302
+ object.foobar("ruby on rails")
303
+
304
+ ==== hash_including
305
+ mock(object).foobar(hash_including(:red => "#FF0000", :blue => "#0000FF"))
306
+ object.foobar({:red => "#FF0000", :blue => "#0000FF", :green => "#00FF00"})
307
+
308
+ ==== satisfy
309
+ mock(object).foobar(satisfy {|arg| arg.length == 2})
310
+ object.foobar("xy")
311
+
312
+ ==== Writing your own Argument Matchers
313
+ Writing a custom argument wildcard matcher is not difficult. See
314
+ RR::WildcardMatchers for details.
315
+
316
+ === Invocation Amount Wildcard Matchers
317
+ ==== any_times
318
+ mock(object).method_name(anything).times(any_times) {return_value}
319
+
320
+ == Special Thanks To
321
+ With any development effort, there are countless people who have contributed
322
+ to making it possible. We all are standing on the shoulders of giants.
323
+ * Andreas Haller for patches
324
+ * Aslak Hellesoy for Developing Rspec
325
+ * Dan North for syntax ideas
326
+ * Dave Astels for some BDD inspiration
327
+ * David Chelimsky for encouragement to make the RR framework, for developing the Rspec mock framework, syntax ideas, and patches
328
+ * Daniel Sudol for identifing performance issues with RR
329
+ * Felix Morio for pairing with me
330
+ * Gerard Meszaros for his excellent book "xUnit Test Patterns"
331
+ * James Mead for developing Mocha
332
+ * Jeff Whitmire for documentation suggestions
333
+ * Jim Weirich for developing Flexmock, the first Terse ruby mock framework in Ruby
334
+ * Joe Ferris for patches
335
+ * Matthew O'Connor for patches and pairing with me
336
+ * Michael Niessner for patches and pairing with me
337
+ * Mike Mangino (from Elevated Rails) for patches and pairing with me
338
+ * Nick Kallen for documentation suggestions, bug reports, and patches
339
+ * Nathan Sobo for various ideas and inspiration for cleaner and more expressive code
340
+ * Parker Thompson for pairing with me
341
+ * Phil Darnowsky for patches
342
+ * Pivotal Labs for sponsoring RR development
343
+ * Stephen Baker for Developing Rspec