redinger-rr 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
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