rr 1.0.5 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +6 -14
  2. data/CHANGES.md +24 -0
  3. data/LICENSE +2 -2
  4. data/README.md +124 -741
  5. data/VERSION +1 -1
  6. data/lib/rr.rb +2 -103
  7. data/lib/rr/adapters/minitest.rb +21 -13
  8. data/lib/rr/adapters/minitest_active_support.rb +34 -0
  9. data/lib/rr/adapters/none.rb +17 -0
  10. data/lib/rr/adapters/{rspec.rb → rspec/invocation_matcher.rb} +2 -27
  11. data/lib/rr/adapters/rspec_1.rb +42 -0
  12. data/lib/rr/adapters/rspec_2.rb +24 -0
  13. data/lib/rr/adapters/test_unit_1.rb +54 -0
  14. data/lib/rr/adapters/test_unit_2.rb +13 -0
  15. data/lib/rr/adapters/test_unit_2_active_support.rb +35 -0
  16. data/lib/rr/autohook.rb +43 -0
  17. data/lib/rr/core_ext/array.rb +12 -0
  18. data/lib/rr/core_ext/enumerable.rb +16 -0
  19. data/lib/rr/core_ext/hash.rb +20 -0
  20. data/lib/rr/core_ext/range.rb +8 -0
  21. data/lib/rr/core_ext/regexp.rb +8 -0
  22. data/lib/rr/double.rb +4 -4
  23. data/lib/rr/double_definitions/double_definition.rb +9 -3
  24. data/lib/rr/errors.rb +21 -0
  25. data/lib/rr/expectations/argument_equality_expectation.rb +10 -7
  26. data/lib/rr/expectations/times_called_expectation.rb +2 -8
  27. data/lib/rr/injections/double_injection.rb +1 -1
  28. data/lib/rr/method_dispatches/base_method_dispatch.rb +1 -1
  29. data/lib/rr/recorded_calls.rb +12 -12
  30. data/lib/rr/space.rb +5 -3
  31. data/lib/rr/times_called_matchers/never_matcher.rb +2 -2
  32. data/lib/rr/wildcard_matchers/anything.rb +2 -2
  33. data/lib/rr/wildcard_matchers/boolean.rb +3 -7
  34. data/lib/rr/wildcard_matchers/duck_type.rb +11 -15
  35. data/lib/rr/wildcard_matchers/hash_including.rb +14 -13
  36. data/lib/rr/wildcard_matchers/is_a.rb +6 -7
  37. data/lib/rr/wildcard_matchers/satisfy.rb +8 -8
  38. data/lib/rr/without_autohook.rb +112 -0
  39. data/rr.gemspec +28 -0
  40. data/spec/global_helper.rb +12 -0
  41. data/spec/suite.rb +93 -0
  42. data/spec/suites/common/adapter_tests.rb +37 -0
  43. data/spec/suites/common/rails_integration_test.rb +175 -0
  44. data/spec/suites/common/test_unit_tests.rb +25 -0
  45. data/spec/suites/minitest/integration/minitest_test.rb +13 -0
  46. data/spec/suites/minitest/test_helper.rb +3 -0
  47. data/spec/suites/rspec_1/integration/rspec_1_spec.rb +20 -0
  48. data/spec/suites/rspec_1/integration/test_unit_1_rails_spec.rb +19 -0
  49. data/spec/suites/rspec_1/integration/test_unit_2_rails_spec.rb +18 -0
  50. data/spec/suites/rspec_1/spec_helper.rb +24 -0
  51. data/spec/suites/rspec_2/functional/any_instance_of_spec.rb +47 -0
  52. data/spec/suites/rspec_2/functional/dont_allow_spec.rb +12 -0
  53. data/spec/suites/rspec_2/functional/dsl_spec.rb +13 -0
  54. data/spec/suites/rspec_2/functional/instance_of_spec.rb +14 -0
  55. data/spec/suites/rspec_2/functional/mock_spec.rb +241 -0
  56. data/spec/suites/rspec_2/functional/proxy_spec.rb +136 -0
  57. data/spec/suites/rspec_2/functional/spy_spec.rb +41 -0
  58. data/spec/suites/rspec_2/functional/strong_spec.rb +79 -0
  59. data/spec/suites/rspec_2/functional/stub_spec.rb +190 -0
  60. data/spec/suites/rspec_2/functional/wildcard_matchers_spec.rb +128 -0
  61. data/spec/suites/rspec_2/integration/minitest_rails_spec.rb +15 -0
  62. data/spec/suites/rspec_2/integration/rspec_2_spec.rb +20 -0
  63. data/spec/suites/rspec_2/integration/test_unit_rails_spec.rb +14 -0
  64. data/spec/suites/rspec_2/spec_helper.rb +27 -0
  65. data/spec/suites/rspec_2/support/matchers/wildcard_matcher_matchers.rb +32 -0
  66. data/spec/suites/rspec_2/support/shared_examples/space.rb +13 -0
  67. data/spec/suites/rspec_2/support/shared_examples/times_called_expectation.rb +9 -0
  68. data/spec/suites/rspec_2/unit/adapters/rr_methods/double_creators_spec.rb +135 -0
  69. data/spec/suites/rspec_2/unit/adapters/rr_methods/space_spec.rb +101 -0
  70. data/spec/suites/rspec_2/unit/adapters/rr_methods/wildcard_matchers_spec.rb +69 -0
  71. data/spec/suites/rspec_2/unit/adapters/rspec/invocation_matcher_spec.rb +297 -0
  72. data/spec/suites/rspec_2/unit/adapters/rspec_spec.rb +85 -0
  73. data/spec/suites/rspec_2/unit/core_ext/array_spec.rb +39 -0
  74. data/spec/suites/rspec_2/unit/core_ext/enumerable_spec.rb +81 -0
  75. data/spec/suites/rspec_2/unit/core_ext/hash_spec.rb +55 -0
  76. data/spec/suites/rspec_2/unit/core_ext/range_spec.rb +41 -0
  77. data/spec/suites/rspec_2/unit/core_ext/regexp_spec.rb +41 -0
  78. data/spec/suites/rspec_2/unit/double_definitions/child_double_definition_create_spec.rb +114 -0
  79. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_blank_slate_spec.rb +93 -0
  80. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_spec.rb +446 -0
  81. data/spec/suites/rspec_2/unit/errors/rr_error_spec.rb +67 -0
  82. data/spec/suites/rspec_2/unit/expectations/any_argument_expectation_spec.rb +48 -0
  83. data/spec/suites/rspec_2/unit/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  84. data/spec/suites/rspec_2/unit/expectations/argument_equality_expectation_spec.rb +135 -0
  85. data/spec/suites/rspec_2/unit/expectations/boolean_argument_equality_expectation_spec.rb +30 -0
  86. data/spec/suites/rspec_2/unit/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  87. data/spec/suites/rspec_2/unit/expectations/satisfy_argument_equality_expectation_spec.rb +61 -0
  88. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/any_times_matcher_spec.rb +22 -0
  89. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_least_matcher_spec.rb +37 -0
  90. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_most_matcher_spec.rb +43 -0
  91. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/integer_matcher_spec.rb +58 -0
  92. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/proc_matcher_spec.rb +35 -0
  93. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/range_matcher_spec.rb +39 -0
  94. data/spec/suites/rspec_2/unit/hash_with_object_id_key_spec.rb +88 -0
  95. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_spec.rb +545 -0
  96. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_verify_spec.rb +32 -0
  97. data/spec/suites/rspec_2/unit/proc_from_block_spec.rb +14 -0
  98. data/spec/suites/rspec_2/unit/rr_spec.rb +28 -0
  99. data/spec/suites/rspec_2/unit/space_spec.rb +595 -0
  100. data/spec/suites/rspec_2/unit/spy_verification_spec.rb +133 -0
  101. data/spec/suites/rspec_2/unit/times_called_matchers/any_times_matcher_spec.rb +46 -0
  102. data/spec/suites/rspec_2/unit/times_called_matchers/at_least_matcher_spec.rb +54 -0
  103. data/spec/suites/rspec_2/unit/times_called_matchers/at_most_matcher_spec.rb +69 -0
  104. data/spec/suites/rspec_2/unit/times_called_matchers/integer_matcher_spec.rb +69 -0
  105. data/spec/suites/rspec_2/unit/times_called_matchers/proc_matcher_spec.rb +54 -0
  106. data/spec/suites/rspec_2/unit/times_called_matchers/range_matcher_spec.rb +75 -0
  107. data/spec/suites/rspec_2/unit/times_called_matchers/times_called_matcher_spec.rb +117 -0
  108. data/spec/suites/rspec_2/unit/wildcard_matchers/anything_spec.rb +33 -0
  109. data/spec/suites/rspec_2/unit/wildcard_matchers/boolean_spec.rb +45 -0
  110. data/spec/suites/rspec_2/unit/wildcard_matchers/duck_type_spec.rb +64 -0
  111. data/spec/suites/rspec_2/unit/wildcard_matchers/hash_including_spec.rb +64 -0
  112. data/spec/suites/rspec_2/unit/wildcard_matchers/is_a_spec.rb +55 -0
  113. data/spec/suites/rspec_2/unit/wildcard_matchers/numeric_spec.rb +46 -0
  114. data/spec/suites/rspec_2/unit/wildcard_matchers/satisfy_spec.rb +57 -0
  115. data/spec/suites/test_unit_1/integration/test_unit_1_test.rb +6 -0
  116. data/spec/suites/test_unit_1/test_helper.rb +7 -0
  117. data/spec/suites/test_unit_2/integration/test_unit_2_test.rb +6 -0
  118. data/spec/suites/test_unit_2/test_helper.rb +3 -0
  119. metadata +183 -19
  120. data/Gemfile +0 -9
  121. data/Rakefile +0 -34
  122. data/lib/rr/adapters/rspec2.rb +0 -30
  123. data/lib/rr/adapters/test_unit.rb +0 -33
  124. data/lib/rr/errors/argument_equality_error.rb +0 -6
  125. data/lib/rr/wildcard_matchers/range.rb +0 -7
  126. data/lib/rr/wildcard_matchers/regexp.rb +0 -7
  127. data/spec/runner.rb +0 -41
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDk5MTU5MzdkN2I5OWEwY2FkNmQ3MzI4MzRmMTlmYzQwYzhkMTUwOA==
5
- data.tar.gz: !binary |-
6
- ODM5Nzc5YzE5OGJmMzZhOWQ5M2YzMzdjM2IzMjAxYzQyOWM1NzQ4Yg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NDk1OGY1YTg5NmFlNTFlYjkyNTQ2ZTE0Njk0NzFmNzllN2I1MDQ2ZDQzZjM4
10
- NjM2MWUxNTZmZmUzNjljM2EwMmU5YjZlMDg4NWFlNWViMzY4MmNhYTg1N2Uw
11
- ODhlZjY5ZTg2M2JhZmJiMmI4YmNhMGRiZDhlZGQxMzM4YjUzYWU=
12
- data.tar.gz: !binary |-
13
- ZWYxYTIxNjVkNDMzNmJjM2I1ODMxMTk1MjA1MDcyZDIzZTFjY2YxYzk0NmFi
14
- ODdkZmJlMzgzZWFjMzZiODk3MzhmOTc5MzEwZTI0YmVlMzJmZmFkOGJhOTVh
15
- MTU5YWY1MWUxOWMwMDk0YTg3NmJkZDJhYzk5OTQwYzQ3NTA5ZDY=
2
+ SHA1:
3
+ metadata.gz: ef054bac4349c5c3f76cc2b3d338b04197427cb7
4
+ data.tar.gz: b518e1419972353a82dabb2132cb75a0866320d4
5
+ SHA512:
6
+ metadata.gz: 427ec24ae2a285c7b2ba881d230c32d7ff0d99c2c3d8e4efe6295b1b368679869b5131ffb53e773c0b4546cf897adfcfd5de3b8423b21944244cdd74cc49a8be
7
+ data.tar.gz: e743dc167bfcb5fbc315042f44ca6df094f9aba0bc0aecac9b1d8b6b0696544a40e1940aa3630bff10437f07b78a519fe5ca69bcc67c346e90ec9192b7b0c266
data/CHANGES.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 (UNRELEASED)
4
+
5
+ * Fix a line in RR::Injections::DoubleInjection to use top-level RR constant
6
+ [Thibaut]
7
+ * Fix all wildcard matches so they work within hashes and arrays. This means
8
+ that `stub([hash_containing(:foo => 'bar')])` will match
9
+ `stub([{:foo => 'bar', :baz => 'qux'}])`.
10
+ * RR now auto-hooks into whichever test framework you have loaded; there is no
11
+ longer a need to `include RR::Adapters::Whatever` into your test framework. If
12
+ you don't like the autohook and prefer the old way, simply use
13
+ `require 'rr/without_autohook'` instead of `require 'rr'`. (There are now
14
+ seven adapters; see lib/rr/adapters for the full list.)
15
+ * Fix Test::Unit adapters to ensure that any additional teardown is completely
16
+ run in the event that RR's verify step produces an error. This was causing
17
+ weirdness when using Test::Unit alongside Rails.
18
+ * Add an explicit Test::Unit / ActiveSupport adapter. As ActiveSupport::TestCase
19
+ introduces its own setup/teardown hooks, use these when autohooking in RR.
20
+ * Upon release, the tests are now packaged up and uploaded to S3. This is for
21
+ Linux distros like Fedora who wrap gems in RPM packages. You can always find
22
+ the latest tests at: <http://s3.amazonaws.com/rubygem-rr/tests/vX.Y.Z.tar.gz>,
23
+ where X.Y.Z represents a version. I have retroactively packaged the tests for
24
+ 1.0.4 and 1.0.5.
25
+ * General cleanup and that sort of thing.
26
+
3
27
  ## 1.0.5 (2013-03-28)
4
28
 
5
29
  * Compatibility with RSpec-2. There are now two adapters for RSpec, one that
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Brian Takita
1
+ Copyright (c) 2010-2013 Brian Takita
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
@@ -19,4 +19,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
19
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
20
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
21
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
- OTHER DEALINGS IN THE SOFTWARE.
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,822 +1,205 @@
1
1
  # RR [![Build Status](https://secure.travis-ci.org/rr/rr.png)](http://travis-ci.org/rr/rr)
2
2
 
3
- RR (Double Ruby) is a test double framework that features a rich selection of
4
- double techniques and a terse syntax.
3
+ RR is a test double framework for Ruby that features a rich selection of double
4
+ techniques and a terse syntax.
5
5
 
6
- To get started, install RR from the command prompt:
7
6
 
8
- ~~~
9
- gem install rr
10
- ~~~
11
-
12
-
13
- ## What is a test double?
14
-
15
- A test double is a generalization of something that replaces a real object to
16
- make it easier to test another object. It's like a stunt double for tests. The
17
- following are test doubles:
18
-
19
- * Mocks
20
- * Stubs
21
- * Fakes
22
- * Spies
23
- * Proxies
24
-
25
- *Learn more: <http://xunitpatterns.com/Test%20Double.html>*
26
-
27
- Currently RR implements mocks, stubs, proxies, and spies. Fakes usually require
28
- custom code, so it is beyond the scope of RR.
29
-
30
-
31
- ## Using RR with your test framework
32
-
33
- ### Test::Unit
34
-
35
- ~~~ ruby
36
- class Test::Unit::TestCase
37
- include RR::Adapters::TestUnit
38
- end
39
- ~~~
40
-
41
- ### RSpec
42
-
43
- RR actually has two adapters, one for the newest version of RSpec (2) and
44
- another for the older version (1). Currently RSpec targets RR's RSpec-1 adapter
45
- and so until this is fixed you will need to specify the RSpec-2 adapter:
46
-
47
- ~~~ ruby
48
- RSpec.configure do |config|
49
- config.include(RR::Adapters::RSpec2)
50
- end
51
- ~~~
52
-
53
- ### MiniTest / MiniSpec
54
-
55
- ~~~ ruby
56
- class MiniTest::Unit::TestCase
57
- include RR::Adapters::MiniTest
58
- end
59
- ~~~
60
-
61
-
62
- ## Syntax between RR and other double/mock frameworks
63
-
64
- ### Terse syntax
65
-
66
- One of the goals of RR is to make doubles more scannable. This is accomplished
67
- by making the double declaration look as much as the actual method invocation as
68
- possible. Here is RR compared to other mock frameworks:
69
-
70
- ~~~ ruby
71
- # Flexmock
72
- flexmock(User).should_receive(:find).with('42').and_return(jane)
73
- # RSpec
74
- User.should_receive(:find).with('42').and_return(jane)
75
- # Mocha
76
- User.expects(:find).with('42').returns { jane }
77
- # rspec-mocks (using return value blocks)
78
- User.should_receive(:find).with('42') { jane }
79
- # RR
80
- mock(User).find('42') { jane }
81
- ~~~
82
-
83
- ### Double injections (aka partial mocking)
84
-
85
- RR utilizes a technique known as "double injection".
86
-
87
- ~~~ ruby
88
- my_object = MyClass.new
89
- mock(my_object).hello
90
- ~~~
91
-
92
- Compare this with doing a mock in Mocha:
93
-
94
- ~~~ ruby
95
- my_mocked_object = mock()
96
- my_mocked_object.expects(:hello)
97
- ~~~
98
-
99
- ### Pure mock objects
100
-
101
- If you wish to use objects for the sole purpose of being a mock, you can do so
102
- by creating an empty object:
103
-
104
- ~~~ ruby
105
- mock(my_mock_object = Object.new).hello
106
- ~~~
107
-
108
- However as a shortcut you can also use #mock!:
109
-
110
- ~~~ ruby
111
- # Create a new mock object with an empty #hello method, then retrieve that mock
112
- # object via the #subject method
113
- my_mock_object = mock!.hello.subject
114
- ~~~
115
-
116
- ### No #should_receive or #expects method
117
-
118
- RR uses #method_missing to set your method expectation. This means you do not
119
- need to use a method such as #should_receive or #expects.
120
-
121
- ~~~ ruby
122
- # In Mocha, #expects sets the #hello method expectation:
123
- my_object.expects(:hello)
124
- # Using rspec-mocks, #should_receive sets the #hello method expectation:
125
- my_object.should_receive(:hello)
126
- # And here's how you say it using RR:
127
- mock(my_object).hello
128
- ~~~
129
-
130
- ### #with method call is not necessary
131
-
132
- The fact that RR uses #method_missing also makes using the #with method
133
- unnecessary in most circumstances to set the argument expectation itself
134
- (although you can still use it if you want):
135
-
136
- ~~~ ruby
137
- # Mocha
138
- my_object.expects(:hello).with('bob', 'jane')
139
- # rspec-mocks
140
- my_object.should_receive(:hello).with('bob', 'jane')
141
- # RR
142
- mock(my_object).hello('bob', 'jane')
143
- mock(my_object).hello.with('bob', 'jane') # same thing, just more verbose
144
- ~~~
145
-
146
- ### Using a block to set the return value
147
-
148
- RR supports using a block to set the return value as opposed to a specific
149
- method call (although again, you can use #returns if you like):
150
-
151
- ~~~ ruby
152
- # Mocha
153
- my_object.expects(:hello).with('bob', 'jane').returns('Hello Bob and Jane')
154
- # rspec-mocks
155
- my_object.should_receive(:hello).with('bob', 'jane') { 'Hello Bob and Jane' }
156
- my_object.should_receive(:hello).with('bob', 'jane').and_return('Hello Bob and Jane') # same thing, just more verbose
157
- # RR
158
- mock(my_object).hello('bob', 'jane') { 'Hello Bob and Jane' }
159
- mock(my_object).hello('bob', 'jane').returns('Hello Bob and Jane') # same thing, just more verbose
160
- ~~~
161
-
162
-
163
- ## Using RR
7
+ ## Getting started
164
8
 
165
- To create a double on an object, you can use the following methods:
166
-
167
- * #mock / #mock!
168
- * #stub / #stub!
169
- * #dont_allow / #dont_allow!
170
- * #proxy / #proxy!
171
- * #instance_of / #instance_of!
172
-
173
- These methods are composable. #mock, #stub, and #dont_allow can be used by
174
- themselves and are mutually exclusive. #proxy and #instance_of must be chained
175
- with #mock or #stub. You can also chain #proxy and #instance_of together.
176
-
177
- The ! (bang) version of these methods causes the subject object of the Double to
178
- be instantiated.
179
-
180
- ### #mock
181
-
182
- \#mock replaces the method on the object with an expectation and implementation.
183
- The expectations are a mock will be called with certain arguments a certain
184
- number of times (the default is once). You can also set the return value of the
185
- method invocation.
186
-
187
- *Learn more: <http://xunitpatterns.com/Mock%20Object.html>*
188
-
189
- The following example sets an expectation that the view will receive a method
190
- call to #render with the arguments `{:partial => "user_info"}` once. When the
191
- method is called, `"Information"` is returned.
9
+ Simply add the following to your Gemfile:
192
10
 
193
11
  ~~~ ruby
194
- view = controller.template
195
- mock(view).render(:partial => "user_info") {"Information"}
12
+ gem 'rr', '~> 1.0.5'
196
13
  ~~~
197
14
 
198
- You can also allow any number of arguments to be passed into the mock like
199
- this:
15
+ If you're on Rails, make sure to add it to the "test" group:
200
16
 
201
17
  ~~~ ruby
202
- mock(view).render.with_any_args.twice do |*args|
203
- if args.first == {:partial => "user_info"}
204
- "User Info"
205
- else
206
- "Stuff in the view #{args.inspect}"
207
- end
18
+ group :test do
19
+ gem 'rr', '~> 1.0.5'
208
20
  end
209
21
  ~~~
210
22
 
211
- ### #stub
212
-
213
- \#stub replaces the method on the object with only an implementation. You can
214
- still use arguments to differentiate which stub gets invoked.
215
-
216
- *Learn more: <http://xunitpatterns.com/Test%20Stub.html>*
217
23
 
218
- The following example makes the User.find method return `jane` when passed "42"
219
- and returns `bob` when passed "99". If another id is passed to User.find, an
220
- exception is raised.
24
+ ## A whirlwind tour of RR
221
25
 
222
- ~~~ ruby
223
- jane = User.new
224
- bob = User.new
225
- stub(User).find('42') {jane}
226
- stub(User).find('99') {bob}
227
- stub(User).find do |id|
228
- raise "Unexpected id #{id.inspect} passed to me"
229
- end
230
- ~~~
231
-
232
- ### #dont_allow (aliased to #do_not_allow, #dont_call, and #do_not_call)
233
-
234
- \#dont_allow is the opposite of #mock -- it sets an expectation on the Double
235
- that it will never be called. If the Double actually does end up being called, a
236
- TimesCalledError is raised.
237
-
238
- ~~~ ruby
239
- dont_allow(User).find('42')
240
- User.find('42') # raises a TimesCalledError
241
- ~~~
242
-
243
- ### `mock.proxy`
244
-
245
- `mock.proxy` replaces the method on the object with an expectation,
246
- implementation, and also invokes the actual method. `mock.proxy` also intercepts
247
- the return value and passes it into the return value block.
248
-
249
- The following example makes sets an expectation that `view.render({:partial =>
250
- "right_navigation"})` gets called once and returns the actual content of the
251
- rendered partial template. A call to `view.render({:partial => "user_info"})`
252
- will render the "user_info" partial template and send the content into the block
253
- and is represented by the `html` variable. An assertion is done on the value of
254
- `html` and `"Different html"` is returned.
255
-
256
- ~~~ ruby
257
- view = controller.template
258
- mock.proxy(view).render(:partial => "right_navigation")
259
- mock.proxy(view).render(:partial => "user_info") do |html|
260
- html.should include("John Doe")
261
- "Different html"
262
- end
263
- ~~~
264
-
265
- You can also use `mock.proxy` to set expectations on the returned value. In the
266
- following example, a call to User.find('5') does the normal ActiveRecord
267
- implementation and passes the actual value, represented by the variable `bob`,
268
- into the block. `bob` is then set with a `mock.proxy` for projects to return only
269
- the first 3 projects. `bob` is also mocked so that #valid? returns false.
270
-
271
- ~~~ ruby
272
- mock.proxy(User).find('5') do |bob|
273
- mock.proxy(bob).projects do |projects|
274
- projects[0..3]
275
- end
276
- mock(bob).valid? { false }
277
- bob
278
- end
279
- ~~~
280
-
281
- ### `stub.proxy`
282
-
283
- Intercept the return value of a method call. The following example verifies
284
- `render(:partial)` will be called and renders the partial.
285
-
286
- ~~~ ruby
287
- view = controller.template
288
- stub.proxy(view).render(:partial => "user_info") do |html|
289
- html.should include("Joe Smith")
290
- html
291
- end
292
- ~~~
293
-
294
- ### #any_instance_of
295
-
296
- Allows stubs to be added to all instances of a class. It works by binding to
297
- methods from the class itself, rather than the eigenclass. This allows all
298
- instances (excluding instances with the method redefined in the eigenclass) to
299
- get the change.
300
-
301
- Due to Ruby runtime limitations, mocks will not work as expected. It's not
302
- obviously feasible (without an ObjectSpace lookup) to support all of RR's
303
- methods (such as mocking). ObjectSpace is not readily supported in JRuby, since
304
- it causes general slowness in the interpreter. I'm of the opinion that test
305
- speed is more important than having mocks on all instances of a class. If there
306
- is another solution, I'd be willing to add it.
307
-
308
- ~~~ ruby
309
- any_instance_of(User) do |u|
310
- stub(u).valid? { false }
311
- end
312
- # or
313
- any_instance_of(User, :valid? => false)
314
- # or
315
- any_instance_of(User, :valid? => lambda { false })
316
- ~~~
317
-
318
- ### Spies
319
-
320
- Adding a DoubleInjection to an object + method (done by #stub, #mock, or
321
- \#dont_allow) causes RR to record any method invocations to the object + method.
322
- Assertions can then be made on the recorded method calls.
323
-
324
- #### Test::Unit
325
-
326
- ~~~ ruby
327
- subject = Object.new
328
- stub(subject).foo
329
- subject.foo(1)
330
- assert_received(subject) {|subject| subject.foo(1) }
331
- assert_received(subject) {|subject| subject.bar } # This fails
332
- ~~~
333
-
334
- #### RSpec
335
-
336
- ~~~ ruby
337
- subject = Object.new
338
- stub(subject).foo
339
- subject.foo(1)
340
- subject.should have_received.foo(1)
341
- subject.should have_received.bar # This fails
342
- ~~~
343
-
344
- ### Block syntax
345
-
346
- The block syntax has two modes:
347
-
348
- * A normal block mode with a DoubleDefinitionCreatorProxy argument:
349
-
350
- ~~~ ruby
351
- script = MyScript.new
352
- mock(script) do |expect|
353
- expect.system("cd #{RAILS_ENV}") {true}
354
- expect.system("rake foo:bar") {true}
355
- expect.system("rake baz") {true}
356
- end
357
- ~~~
358
-
359
- * An instance_eval mode where the DoubleDefinitionCreatorProxy is
360
- instance_eval'ed:
361
-
362
- ~~~ ruby
363
- script = MyScript.new
364
- mock(script) do
365
- system("cd #{RAILS_ENV}") {true}
366
- system("rake foo:bar") {true}
367
- system("rake baz") {true}
368
- end
369
- ~~~
370
-
371
- ### Double graphs
372
-
373
- RR has a method-chaining API support for double graphs. For example, let's say
374
- you want an object to receive a method call to #foo, and have the return value
375
- receive a method call to #bar.
376
-
377
- In RR, you would do:
378
-
379
- ~~~ ruby
380
- stub(object).foo.stub!.bar { :baz }
381
- object.foo.bar #=> :baz
382
- # or:
383
- stub(object).foo { stub!.bar {:baz} }
384
- object.foo.bar #=> :baz
385
- # or:
386
- bar = stub!.bar { :baz }
387
- stub(object).foo { bar }
388
- object.foo.bar #=> :baz
389
- ~~~
390
-
391
- ### Modifying doubles
392
-
393
- Whenever you create a double by calling a method on an object you've wrapped,
394
- you get back a special object: a DoubleDefinition. In other words:
395
-
396
- ~~~ ruby
397
- stub(object).foo #=> RR::DoubleDefinitions::DoubleDefinition
398
- ~~~
399
-
400
- There are several ways you can modify the behavior of these doubles via the
401
- DoubleDefinition API, and they are listed in this section.
402
-
403
- Quick note: all of these methods accept blocks as a shortcut for setting the
404
- return value at the same time. In other words, if you have something like this:
405
-
406
- ~~~ ruby
407
- mock(object).foo { 'bar' }
408
- ~~~
409
-
410
- you can modify the mock and keep the return value like so:
411
-
412
- ~~~ ruby
413
- mock(object).foo.times(2) { 'bar' }
414
- ~~~
415
-
416
- You can even flip around the block:
417
-
418
- ~~~ ruby
419
- mock(object).foo { 'bar' }.times(2)
420
- ~~~
421
-
422
- And as we explain below, this is just a shortcut for:
423
-
424
- ~~~ ruby
425
- mock(object).foo.returns { 'bar' }.times(2)
426
- ~~~
427
-
428
- #### Stubbing method implementation / return value
429
-
430
- There are two ways here. We have already covered this usage:
431
-
432
- ~~~ ruby
433
- stub(object).foo { 'bar' }
434
- ~~~
435
-
436
- However, you can also use #returns if it's more clear to you:
437
-
438
- ~~~ ruby
439
- stub(object).foo.returns { 'bar' }
440
- ~~~
441
-
442
- Regardless, keep in mind that you're actually supplying the implementation of
443
- the method in question here, so you can put whatever you want in this block:
444
-
445
- ~~~ ruby
446
- stub(object).foo { |age, count|
447
- raise 'hell' if age < 16
448
- ret = yield count
449
- blue? ? ret : 'whatever'
450
- }
451
- ~~~
452
-
453
- This works for mocks as well as stubs.
454
-
455
- #### Stubbing method implementation based on argument expectation
456
-
457
- A double's implementation is always tied to its argument expectation. This means
458
- that it is possible to return one value if the method is called one way and
459
- return a second value if the method is called a second way. For example:
460
-
461
- ~~~ ruby
462
- stub(object).foo { 'bar' }
463
- stub(object).foo(1, 2) { 'baz' }
464
- object.foo #=> 'bar'
465
- object.foo(1, 2) #=> 'baz'
466
- ~~~
467
-
468
- This works for mocks as well as stubs.
469
-
470
- #### Stubbing method to yield given block
471
-
472
- If you need to stub a method such that a block given to it is guaranteed to be
473
- called when the method is called, then use #yields.
474
-
475
- ~~~ ruby
476
- # This outputs: [1, 2, 3]
477
- stub(object).foo.yields(1, 2, 3)
478
- object.foo {|*args| pp args }
479
- ~~~
480
-
481
- This works for mocks as well as stubs.
482
-
483
- #### Expecting method to be called with exact argument list
484
-
485
- There are two ways to do this. Here is the way we have shown before:
486
-
487
- ~~~ ruby
488
- mock(object).foo(1, 2)
489
- object.foo(1, 2) # ok
490
- object.foo(3) # fails
491
- ~~~
492
-
493
- But if this is not clear enough to you, you can use #with:
494
-
495
- ~~~ ruby
496
- mock(object).foo.with(1, 2)
497
- object.foo(1, 2) # ok
498
- object.foo(3) # fails
499
- ~~~
500
-
501
- As seen above, if you create an the expectation for a set of arguments and the
502
- method is called with another set of arguments, even if *those* arguments are of
503
- a completely different size, you will need to create another expectation for
504
- them somehow. A simple way to do this is to #stub the method beforehand:
26
+ ### Stubs
505
27
 
506
28
  ~~~ ruby
29
+ # Stub a method to return nothing
507
30
  stub(object).foo
508
- mock(object).foo(1, 2)
509
- object.foo(1, 2) # ok
510
- object.foo(3) # ok too
511
- ~~~
512
-
513
- #### Expecting method to be called with any arguments
514
-
515
- Use #with_any_args:
516
-
517
- ~~~ ruby
518
- mock(object).foo.with_any_args
519
- object.foo # ok
520
- object.foo(1) # also ok
521
- object.foo(1, 2) # also ok
522
- # ... you get the idea
523
- ~~~
524
-
525
- #### Expecting method to be called with no arguments
526
-
527
- Use #with_no_args:
528
-
529
- ~~~ ruby
530
- mock(object).foo.with_no_args
531
- object.foo # ok
532
- object.foo(1) # fails
533
- ~~~
534
-
535
- #### Expecting method to never be called
31
+ stub(MyClass).foo
536
32
 
537
- Use #never:
33
+ # Stub a method to always return a value
34
+ stub(object).foo { 'bar' }
35
+ stub(MyClass).foo { 'bar' }
538
36
 
539
- ~~~ ruby
540
- mock(object).foo.never
541
- object.foo # fails
37
+ # Stub a method to return a value when called with certain arguments
38
+ stub(object).foo(1, 2) { 'bar' }
39
+ stub(MyClass).foo(1, 2) { 'bar' }
542
40
  ~~~
543
41
 
544
- You can also narrow the negative expectation to a specific set of arguments.
545
- Of course, you will still need to set explicit expectations for any other ways
546
- that your method could be called. For instance:
42
+ ### Mocks
547
43
 
548
44
  ~~~ ruby
549
- mock(object).foo.with(1, 2).never
550
- object.foo(3, 4) # fails
551
- ~~~
45
+ # Create an expectation on a method
46
+ mock(object).foo
47
+ mock(MyClass).foo
552
48
 
553
- RR will complain here that this is an unexpected invocation, so we need to add
554
- an expectation for this beforehand. We can do this easily with #stub:
49
+ # Create an expectation on a method and stub it to always return a value
50
+ mock(object).foo { 'bar' }
51
+ mock(MyClass).foo { 'bar' }
555
52
 
556
- ~~~ ruby
557
- stub(object).foo
53
+ # Create an expectation on a method with certain arguments and stub it to return
54
+ # a value when called that way
55
+ mock(object).foo(1, 2) { 'bar' }
56
+ mock(MyClass).foo(1, 2) { 'bar' }
558
57
  ~~~
559
58
 
560
- So, a full example would look like:
59
+ ### Spies
561
60
 
562
61
  ~~~ ruby
62
+ # RSpec
563
63
  stub(object).foo
564
- mock(object).foo.with(1, 2).never
565
- object.foo(3, 4) # ok
566
- object.foo(1, 2) # fails
567
- ~~~
64
+ expect(object).to have_received.foo
568
65
 
569
- Alternatively, you can also use #dont_allow, although the same rules apply as
570
- above:
571
-
572
- ~~~ ruby
66
+ # Test::Unit
573
67
  stub(object).foo
574
- dont_allow(object).foo.with(1, 2)
575
- object.foo(3, 4) # ok
576
- object.foo(1, 2) # fails
577
- ~~~
578
-
579
- #### Expecting method to be called only once
580
-
581
- Use #once:
582
-
583
- ~~~ ruby
584
- mock(object).foo.once
585
- object.foo
586
- object.foo # fails
587
- ~~~
588
-
589
- #### Expecting method to called exact number of times
590
-
591
- Use #times:
592
-
593
- ~~~ ruby
594
- mock(object).foo.times(3)
595
- object.foo
596
- object.foo
597
- object.foo
598
- object.foo # fails
599
- ~~~
600
-
601
- #### Expecting method to be called minimum number of times
602
-
603
- Use #at_least.
604
-
605
- For instance, this would pass:
606
-
607
- ~~~ ruby
608
- mock(object).foo.at_least(3)
609
- object.foo
610
- object.foo
611
- object.foo
612
- object.foo
613
- ~~~
614
-
615
- But this would fail:
616
-
617
- ~~~ ruby
618
- mock(object).foo.at_least(3)
619
- object.foo
620
- object.foo
621
- ~~~
622
-
623
- #### Expecting method to be called maximum number of times
624
-
625
- Use #at_most.
626
-
627
- For instance, this would pass:
628
-
629
- ~~~ ruby
630
- mock(object).foo.at_most(3)
631
- object.foo
632
- object.foo
68
+ assert_received(object) {|o| o.foo }
633
69
  ~~~
634
70
 
635
- But this would fail:
71
+ ### Proxies
636
72
 
637
73
  ~~~ ruby
638
- mock(object).foo.at_most(3)
639
- object.foo
640
- object.foo
641
- object.foo
642
- object.foo
643
- ~~~
74
+ # Intercept a existing method without completely overriding it, and create a
75
+ # new return value from the existing one
76
+ stub.proxy(object).foo {|str| str.upcase }
77
+ stub.proxy(MyClass).foo {|str| str.upcase }
644
78
 
645
- #### Expecting method to be called any number of times
79
+ # Do the same thing except also create an expectation
80
+ mock.proxy(object).foo {|str| str.upcase }
81
+ mock.proxy(MyClass).foo {|str| str.upcase }
646
82
 
647
- Use #any_times. This effectively disables the times-called expectation.
83
+ # Intercept a class's new method and define a double on the return value
84
+ stub.proxy(MyClass).new {|obj| stub(obj).foo; obj }
648
85
 
649
- ~~~ ruby
650
- mock(object).foo.any_times
651
- object.foo
652
- object.foo
653
- object.foo
654
- ...
86
+ # Do the same thing except also create an expectation on .new
87
+ mock.proxy(MyClass).new {|obj| stub(obj).foo; obj }
655
88
  ~~~
656
89
 
657
- You can also use #times + the argument invocation #any_times matcher:
90
+ ### Class instances
658
91
 
659
92
  ~~~ ruby
660
- mock(object).foo.times(any_times)
661
- object.foo
662
- object.foo
663
- object.foo
664
- ...
665
- ~~~
666
-
667
-
668
-
669
- ### Argument wildcard matchers
670
-
671
- RR also has several methods which you can use with argument expectations which
672
- act as placeholders for arguments. When RR goes to verify the argument
673
- expectation it will compare the placeholders with the actual arguments the
674
- method was called with, and if they match then the test passes (hence
675
- "matchers").
676
-
677
- #### #anything
678
-
679
- Matches any value.
93
+ # Stub a method on an instance of MyClass when it is created
94
+ any_instance_of(MyClass) do |klass|
95
+ stub(klass).foo { 'bar' }
96
+ end
680
97
 
681
- ~~~ ruby
682
- mock(object).foobar(1, anything)
683
- object.foobar(1, :my_symbol)
98
+ # Another way to do this which gives you access to the instance itself
99
+ stub.proxy(MyClass).new do |obj|
100
+ stub(obj).foo { 'bar' }
101
+ end
684
102
  ~~~
685
103
 
686
- #### #is_a
687
104
 
688
- Matches an object which `.is_a?(*Class*)`.
105
+ ## Learning more
689
106
 
690
- ~~~ ruby
691
- mock(object).foobar(is_a(Time))
692
- object.foobar(Time.now)
693
- ~~~
107
+ 1. [What is a test double?](doc/01_test_double.md)
108
+ 2. [Using RR with your test framework](doc/02_test_framework_integration.md)
109
+ 3. [Syntax between RR and other double/mock frameworks](doc/03_syntax_comparison.md)
110
+ 4. [API overview](doc/04_api_overview.md)
694
111
 
695
- #### #numeric
696
112
 
697
- Matches a value which `.is_a?(Numeric)`.
113
+ ## Help!
698
114
 
699
- ~~~ ruby
700
- mock(object).foobar(numeric)
701
- object.foobar(99)
702
- ~~~~
115
+ While I may add one later, RR does not have a mailing list at this time, so if
116
+ you have a question simply [post it as an issue](http://github.com/rr/rr/issues)
117
+ and I'll respond as soon as I can.
703
118
 
704
- #### #boolean
705
119
 
706
- Matches true or false.
120
+ ## Contributing
707
121
 
708
- ~~~ ruby
709
- mock(object).foobar(boolean)
710
- object.foobar(false)
711
- ~~~
122
+ Want to contribute a bugfix or new feature to RR? Great! Follow these steps:
712
123
 
713
- #### #duck_type
124
+ 1. If you haven't already, install Ruby 2.0.0-p0 (this is the primary Ruby
125
+ version that RR targets).
126
+ 2. Clone the repo (you probably knew that already).
127
+ 3. Make a new branch off of `master` with a descriptive name.
128
+ 4. Work on your bugfix or feature.
129
+ 5. Run `bundle install`.
130
+ 6. Ensure all of the tests pass by running `bundle exec rake`.
131
+ 7. If you want to go the extra mile, install the other Ruby versions listed
132
+ below in the compatibility table, and repeat steps 5-6. See the "Running test
133
+ suites" section below for more information.
134
+ 8. When you're done, come back to this repo and create a pull request from your
135
+ branch. I'll respond as soon as I can.
714
136
 
715
- Matches an object which responds to certain methods.
137
+ ### Running test suites
716
138
 
717
- ~~~ ruby
718
- mock(object).foobar(duck_type(:walk, :talk))
719
- arg = Object.new
720
- def arg.walk; 'waddle'; end
721
- def arg.talk; 'quack'; end
722
- object.foobar(arg)
723
- ~~~
139
+ In order to test support for multiple Ruby versions and environments, there are
140
+ multiple test suites, and Rake tasks to run these suites. Here is the list of
141
+ available Rake tasks under Ruby >= 1.9:
724
142
 
725
- #### Ranges
143
+ rake spec:rspec_2
144
+ rake spec:minitest
145
+ rake spec:test_unit_2
726
146
 
727
- Matches a number within a certain range.
147
+ Here is the list under Ruby 1.8:
728
148
 
729
- ~~~ ruby
730
- mock(object).foobar(1..10)
731
- object.foobar(5)
732
- ~~~
149
+ rake spec:rspec_1
150
+ rake spec:test_unit_2
151
+ rake spec:test_unit_1
733
152
 
734
- #### Regexps
153
+ As a shortcut, to run all the available suites under the Ruby version you are
154
+ on, you can simply say:
735
155
 
736
- Matches a string which matches a certain regex.
156
+ rake
737
157
 
738
- ~~~ ruby
739
- mock(object).foobar(/on/)
740
- object.foobar("ruby on rails")
741
- ~~~
158
+ (Incidentally, this is also the command which Travis runs.)
742
159
 
743
- #### #hash_including
160
+ Finally, to aid development only, if you're using rbenv, you can run all of the
161
+ tests on all of the Rubies easily with:
744
162
 
745
- Matches a hash which contains a subset of keys and values.
163
+ script/run_full_test_suite
746
164
 
747
- ~~~ ruby
748
- mock(object).foobar(hash_including(:red => "#FF0000", :blue => "#0000FF"))
749
- object.foobar({:red => "#FF0000", :blue => "#0000FF", :green => "#00FF00"})
750
- ~~~
165
+ This requires that you have the
166
+ [rbenv-only](https://github.com/rodreegez/rbenv-only) plugin installed, and of
167
+ course, the necessary Rubies as well too.
751
168
 
752
- #### #satisfy
753
169
 
754
- Matches an argument which satisfies a custom requirement.
170
+ ## Compatibility
755
171
 
756
- ~~~ ruby
757
- mock(object).foobar(satisfy {|arg| arg.length == 2 })
758
- object.foobar("xy")
759
- ~~~
172
+ RR is designed and tested to work against the following test frameworks and Ruby
173
+ versions:
760
174
 
761
- #### Writing your own argument matchers
175
+ | | Ruby 1.8.7-p371 | Ruby 1.9.3-p392 | Ruby 2.0.0-p0 | JRuby 1.7.3 (1.9 mode) |
176
+ |-----------------------|:---------------:|:---------------:|:-------------:|:----------------------:|
177
+ | MiniTest 4.x | | ✓ | ✓ | ✓ |
178
+ | Test::Unit (Ruby 1.8) | ✓ | | | |
179
+ | Test::Unit (Ruby 1.8) + Rails 2.x | ✓ | | | |
180
+ | Test::Unit 2.x | ✓ | ✓ | ✓ | ✓ |
181
+ | Test::Unit 2.x + Rails 2.x | ✓ | | | |
182
+ | Test::Unit 2.x + Rails 3.x | | ✓ | ✓ | ✓ |
183
+ | RSpec 1.x | ✓ | | | |
184
+ | RSpec 2.x | | ✓ | ✓ | ✓ |
762
185
 
763
- Writing a custom argument wildcard matcher is not difficult. See
764
- RR::WildcardMatchers for details.
765
186
 
766
- ### Invocation amount wildcard matchers
187
+ ## Author/Contact
767
188
 
768
- #### #any_times
189
+ RR was originally written by Brian Takita. It is currently maintained by Elliot
190
+ Winkler (<elliot.winkler@gmail.com>).
769
191
 
770
- Only used with #times and matches any number.
771
192
 
772
- ~~~ ruby
773
- mock(object).foo.times(any_times) { return_value }
774
- object.foo
775
- object.foo
776
- object.foo
777
- ...
778
- ~~~
193
+ ## Credits
779
194
 
195
+ With any development effort, there are countless people who have contributed to
196
+ making it possible. We all are standing on the shoulders of giants! [You can
197
+ read all the credits here](CREDITS.md). (Incidentally, if you've directly
198
+ contributed to RR and I haven't included you in this list, please let me know.
199
+ Thanks!)
780
200
 
781
- ## Special thanks to
782
201
 
783
- With any development effort, there are countless people who have contributed to
784
- making it possible. We all are standing on the shoulders of giants. If you have
785
- directly contributed to RR and I missed you in this list, please let me know and
786
- I will add you. Thanks!
787
-
788
- * Andreas Haller for patches
789
- * Aslak Hellesoy for Developing RSpec
790
- * Bryan Helmkamp for patches
791
- * Caleb Spare for patches
792
- * Christopher Redinger for patches
793
- * Dan North for syntax ideas
794
- * Dave Astels for some BDD inspiration
795
- * Dave Myron for a bug report
796
- * David Chelimsky for encouragement to make the RR framework, for developing the
797
- RSpec mock framework, syntax ideas, and patches
798
- * Daniel Sudol for identifing performance issues with RR
799
- * Dmitry Ratnikov for patches
800
- * Eugene Pimenov for patches
801
- * Evan Phoenix for patches
802
- * Felix Morio for pairing with me
803
- * Gabriel Horner for patches
804
- * Gavin Miller for patches
805
- * Gerard Meszaros for his excellent book "xUnit Test Patterns"
806
- * James Mead for developing Mocha
807
- * Jeff Whitmire for documentation suggestions
808
- * Jim Weirich for developing Flexmock, the first Terse ruby mock framework in Ruby
809
- * Joe Ferris for patches
810
- * Matthew O'Connor for patches and pairing with me
811
- * Michael Niessner for patches and pairing with me
812
- * Mike Mangino (from Elevated Rails) for patches and pairing with me
813
- * Myron Marston for bug reports
814
- * Nick Kallen for documentation suggestions, bug reports, and patches
815
- * Nathan Sobo for various ideas and inspiration for cleaner and more expressive code
816
- * Parker Thompson for pairing with me
817
- * Phil Darnowsky for patches
818
- * Pivotal Labs for sponsoring RR development
819
- * Steven Baker for Developing RSpec
820
- * Tatsuya Ono for patches
821
- * Tuomas Kareinen for a bug report
202
+ ## License
822
203
 
204
+ RR is available under the MIT license. Read [LICENSE](LICENSE) for the full
205
+ scoop.