jferris-rr 0.7.1.0.1239654108

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