muack 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitmodules +3 -0
- data/.travis.yml +11 -0
- data/CHANGES.md +5 -0
- data/Gemfile +7 -0
- data/LICENSE +201 -0
- data/README.md +494 -0
- data/Rakefile +18 -0
- data/lib/muack.rb +77 -0
- data/lib/muack/any_instance_of.rb +4 -0
- data/lib/muack/definition.rb +5 -0
- data/lib/muack/failure.rb +38 -0
- data/lib/muack/mock.rb +167 -0
- data/lib/muack/modifier.rb +29 -0
- data/lib/muack/proxy.rb +39 -0
- data/lib/muack/satisfy.rb +54 -0
- data/lib/muack/session.rb +12 -0
- data/lib/muack/stub.rb +22 -0
- data/lib/muack/test.rb +26 -0
- data/lib/muack/version.rb +4 -0
- data/muack.gemspec +53 -0
- data/task/.gitignore +1 -0
- data/task/gemgem.rb +268 -0
- data/test/test_any_instance_of.rb +30 -0
- data/test/test_mock.rb +170 -0
- data/test/test_proxy.rb +77 -0
- data/test/test_readme.rb +16 -0
- data/test/test_satisfy.rb +200 -0
- data/test/test_stub.rb +62 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ee7881104f617fa965f32fb46340cd71f6de26d5
|
4
|
+
data.tar.gz: 5047ee579c7fdf9118139d34823c53d1224abbd2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 10d056827ffb86c201c3720019782e510168a288186b057f4b25f0550a90448fa91b77dd87c36eb976bd94eff8b0600e4bc0dc8d1f4ccdf6c904bc280594838e
|
7
|
+
data.tar.gz: 433d4c055de69a0fd83251aa3e4b0b1e1a012753690470c6b5d738ad7452f1b6e6f9eca586a1fe24c87c4b19c7d19d226c324b14d8f424f8009cd8f5ed3158ec
|
data/.gitmodules
ADDED
data/.travis.yml
ADDED
data/CHANGES.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
Apache License
|
2
|
+
Version 2.0, January 2004
|
3
|
+
http://www.apache.org/licenses/
|
4
|
+
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6
|
+
|
7
|
+
1. Definitions.
|
8
|
+
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
11
|
+
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13
|
+
the copyright owner that is granting the License.
|
14
|
+
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
16
|
+
other entities that control, are controlled by, or are under common
|
17
|
+
control with that entity. For the purposes of this definition,
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
19
|
+
direction or management of such entity, whether by contract or
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22
|
+
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24
|
+
exercising permissions granted by this License.
|
25
|
+
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
27
|
+
including but not limited to software source code, documentation
|
28
|
+
source, and configuration files.
|
29
|
+
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
31
|
+
transformation or translation of a Source form, including but
|
32
|
+
not limited to compiled object code, generated documentation,
|
33
|
+
and conversions to other media types.
|
34
|
+
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
36
|
+
Object form, made available under the License, as indicated by a
|
37
|
+
copyright notice that is included in or attached to the work
|
38
|
+
(an example is provided in the Appendix below).
|
39
|
+
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46
|
+
the Work and Derivative Works thereof.
|
47
|
+
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
49
|
+
the original version of the Work and any modifications or additions
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
61
|
+
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
64
|
+
subsequently incorporated within the Work.
|
65
|
+
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
72
|
+
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78
|
+
where such license applies only to those patent claims licensable
|
79
|
+
by such Contributor that are necessarily infringed by their
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
82
|
+
institute patent litigation against any entity (including a
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
85
|
+
or contributory patent infringement, then any patent licenses
|
86
|
+
granted to You under this License for that Work shall terminate
|
87
|
+
as of the date such litigation is filed.
|
88
|
+
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
91
|
+
modifications, and in Source or Object form, provided that You
|
92
|
+
meet the following conditions:
|
93
|
+
|
94
|
+
(a) You must give any other recipients of the Work or
|
95
|
+
Derivative Works a copy of this License; and
|
96
|
+
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
98
|
+
stating that You changed the files; and
|
99
|
+
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
102
|
+
attribution notices from the Source form of the Work,
|
103
|
+
excluding those notices that do not pertain to any part of
|
104
|
+
the Derivative Works; and
|
105
|
+
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
108
|
+
include a readable copy of the attribution notices contained
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
111
|
+
of the following places: within a NOTICE text file distributed
|
112
|
+
as part of the Derivative Works; within the Source form or
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
114
|
+
within a display generated by the Derivative Works, if and
|
115
|
+
wherever such third-party notices normally appear. The contents
|
116
|
+
of the NOTICE file are for informational purposes only and
|
117
|
+
do not modify the License. You may add Your own attribution
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
120
|
+
that such additional attribution notices cannot be construed
|
121
|
+
as modifying the License.
|
122
|
+
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
124
|
+
may provide additional or different license terms and conditions
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
128
|
+
the conditions stated in this License.
|
129
|
+
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
133
|
+
this License, without any additional terms or conditions.
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135
|
+
the terms of any separate license agreement you may have executed
|
136
|
+
with Licensor regarding such Contributions.
|
137
|
+
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
140
|
+
except as required for reasonable and customary use in describing the
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
142
|
+
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
152
|
+
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
158
|
+
incidental, or consequential damages of any character arising as a
|
159
|
+
result of this License or out of the use or inability to use the
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
162
|
+
other commercial damages or losses), even if such Contributor
|
163
|
+
has been advised of the possibility of such damages.
|
164
|
+
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168
|
+
or other liability obligations and/or rights consistent with this
|
169
|
+
License. However, in accepting such obligations, You may act only
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
174
|
+
of your accepting any such warranty or additional liability.
|
175
|
+
|
176
|
+
END OF TERMS AND CONDITIONS
|
177
|
+
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
179
|
+
|
180
|
+
To apply the Apache License to your work, attach the following
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182
|
+
replaced with your own identifying information. (Don't include
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
184
|
+
comment syntax for the file format. We also recommend that a
|
185
|
+
file or class name and description of purpose be included on the
|
186
|
+
same "printed page" as the copyright notice for easier
|
187
|
+
identification within third-party archives.
|
188
|
+
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
190
|
+
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192
|
+
you may not use this file except in compliance with the License.
|
193
|
+
You may obtain a copy of the License at
|
194
|
+
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
196
|
+
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200
|
+
See the License for the specific language governing permissions and
|
201
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,494 @@
|
|
1
|
+
# Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack)
|
2
|
+
|
3
|
+
by Lin Jen-Shin ([godfat](http://godfat.org))
|
4
|
+
|
5
|
+
## LINKS:
|
6
|
+
|
7
|
+
* [github](https://github.com/godfat/muack)
|
8
|
+
* [rubygems](https://rubygems.org/gems/muack)
|
9
|
+
* [rdoc](http://rdoc.info/github/godfat/muack)
|
10
|
+
|
11
|
+
## DESCRIPTION:
|
12
|
+
|
13
|
+
Muack -- Yet another mocking library.
|
14
|
+
|
15
|
+
Basically it's an [RR][] clone, but much faster under heavy use.
|
16
|
+
It's 32x times faster (750s vs 23s) for running [Rib][] tests.
|
17
|
+
|
18
|
+
[RR]: https://github.com/rr/rr
|
19
|
+
[Rib]: https://github.com/godfat/rib
|
20
|
+
|
21
|
+
## REQUIREMENTS:
|
22
|
+
|
23
|
+
* Tested with MRI (official CRuby) 1.9.3, 2.0.0, Rubinius and JRuby.
|
24
|
+
|
25
|
+
## INSTALLATION:
|
26
|
+
|
27
|
+
gem install muack
|
28
|
+
|
29
|
+
## SYNOPSIS:
|
30
|
+
|
31
|
+
Basically it's an [RR][] clone. Let's see a [Bacon][] example.
|
32
|
+
|
33
|
+
``` ruby
|
34
|
+
require 'bacon'
|
35
|
+
require 'muack'
|
36
|
+
|
37
|
+
include Muack::API
|
38
|
+
|
39
|
+
describe 'Hello' do
|
40
|
+
before{ Muack.reset }
|
41
|
+
after { Muack.verify }
|
42
|
+
|
43
|
+
should 'say world!' do
|
44
|
+
str = 'Hello'
|
45
|
+
mock(str).say('!'){ |arg| "World#{arg}" }
|
46
|
+
str.say('!').should.equal 'World!'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
[Bacon]: https://github.com/chneukirchen/bacon
|
52
|
+
|
53
|
+
### Coming from RR?
|
54
|
+
|
55
|
+
Basically since it's an RR clone, the APIs are much the same.
|
56
|
+
Let's see what's the different with code snippets. All codes
|
57
|
+
were extracted from
|
58
|
+
[RR's API document](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md).
|
59
|
+
|
60
|
+
#### [mock](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#mock)
|
61
|
+
|
62
|
+
`mock` is the same as RR.
|
63
|
+
|
64
|
+
``` ruby
|
65
|
+
view = controller.template
|
66
|
+
mock(view).render(:partial => "user_info") {"Information"}
|
67
|
+
```
|
68
|
+
|
69
|
+
There's no `twice` modifier in Muack, use `times(2)` instead.
|
70
|
+
|
71
|
+
``` ruby
|
72
|
+
mock(view).render.with_any_args.times(2) do |*args|
|
73
|
+
if args.first == {:partial => "user_info"}
|
74
|
+
"User Info"
|
75
|
+
else
|
76
|
+
"Stuff in the view #{args.inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
#### [stub](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#stub)
|
82
|
+
|
83
|
+
`stub` is the same as RR.
|
84
|
+
|
85
|
+
``` ruby
|
86
|
+
jane = User.new
|
87
|
+
bob = User.new
|
88
|
+
stub(User).find('42') {jane}
|
89
|
+
stub(User).find('99') {bob}
|
90
|
+
stub(User).find do |id|
|
91
|
+
raise "Unexpected id #{id.inspect} passed to me"
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
#### [times(0)](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#dont_allow-aliased-to-do_not_allow-dont_call-and-do_not_call)
|
96
|
+
|
97
|
+
There's no dont_allow method in Muack, use `times(0)` instead.
|
98
|
+
|
99
|
+
``` ruby
|
100
|
+
User.find('42').times(0)
|
101
|
+
User.find('42') # raises a Muack::Unexpected
|
102
|
+
```
|
103
|
+
|
104
|
+
#### [mock_proxy](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#mockproxy)
|
105
|
+
|
106
|
+
Since I don't see how we gain from calling it mock.proxy, in Muack we
|
107
|
+
just call it `mock_proxy`.
|
108
|
+
|
109
|
+
``` ruby
|
110
|
+
view = controller.template
|
111
|
+
mock_proxy(view).render(:partial => "right_navigation")
|
112
|
+
mock_proxy(view).render(:partial => "user_info") do |html|
|
113
|
+
html.should include("John Doe")
|
114
|
+
"Different html"
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
#### [stub_proxy](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#stubproxy)
|
119
|
+
|
120
|
+
The same goes to `stub_proxy`.
|
121
|
+
|
122
|
+
``` ruby
|
123
|
+
view = controller.template
|
124
|
+
stub_proxy(view).render(:partial => "user_info") do |html|
|
125
|
+
html.should include("Joe Smith")
|
126
|
+
html
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
#### [any_instance_of](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#any_instance_of)
|
131
|
+
|
132
|
+
Only this form of `any_instance_of` is supported. On the other hand,
|
133
|
+
any of the above is supported as well, not only stub.
|
134
|
+
|
135
|
+
``` ruby
|
136
|
+
any_instance_of(User) do |u|
|
137
|
+
stub(u).valid? { false }
|
138
|
+
mock(u).errors { [] }
|
139
|
+
mock_proxy.save
|
140
|
+
stub_proxy.reload
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### [Block form](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#block-syntax)
|
145
|
+
|
146
|
+
Block form is also supported. However we don't support `instance_eval` form.
|
147
|
+
There's little point to use instance_eval since it's much more complicated
|
148
|
+
and much slower.
|
149
|
+
|
150
|
+
``` ruby
|
151
|
+
script = MyScript.new
|
152
|
+
mock(script) do |expect|
|
153
|
+
expect.system("cd #{RAILS_ENV}") {true}
|
154
|
+
expect.system("rake foo:bar") {true}
|
155
|
+
expect.system("rake baz") {true}
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
#### [Nested mocks](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#double-graphs)
|
160
|
+
|
161
|
+
The shortest API (which might be a bit tricky) is not supported,
|
162
|
+
but we do support:
|
163
|
+
|
164
|
+
``` ruby
|
165
|
+
stub(object).foo { stub.bar{ :baz }.object }
|
166
|
+
object.foo.bar #=> :baz
|
167
|
+
```
|
168
|
+
|
169
|
+
And of course the verbose way:
|
170
|
+
|
171
|
+
``` ruby
|
172
|
+
bar = stub.bar{ :baz }.object
|
173
|
+
stub(object).foo { bar }
|
174
|
+
object.foo.bar #=> :baz
|
175
|
+
```
|
176
|
+
|
177
|
+
Or even more verbose, of course:
|
178
|
+
|
179
|
+
``` ruby
|
180
|
+
bar = Object.new
|
181
|
+
stub(bar).bar{ :baz }
|
182
|
+
stub(object).foo { bar }
|
183
|
+
object.foo.bar #=> :baz
|
184
|
+
```
|
185
|
+
|
186
|
+
#### [Modifier](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#modifying-doubles)
|
187
|
+
|
188
|
+
After defining a mock method, you get a `Muack::Modifier` back.
|
189
|
+
|
190
|
+
``` ruby
|
191
|
+
stub(object).foo #=> Muack::Modifier
|
192
|
+
```
|
193
|
+
|
194
|
+
However, you cannot flip around methods like RR. Whenever you define a
|
195
|
+
mock/stub method, you must provide the block immediately.
|
196
|
+
|
197
|
+
``` ruby
|
198
|
+
mock(object).foo{ 'bar' }.times(2)
|
199
|
+
```
|
200
|
+
|
201
|
+
If unfortunately, the method name you want to mock is already defined,
|
202
|
+
you can call `method_missing` directly to mock it. For example, `inspect`
|
203
|
+
is already defined in `Muack::Mock` to avoid crashing with [Bacon][].
|
204
|
+
In this case, you should do this to mock `inspect`:
|
205
|
+
|
206
|
+
``` ruby
|
207
|
+
mock(object).method_missing(:inspect){ 'bar' }.times(2)
|
208
|
+
```
|
209
|
+
|
210
|
+
#### [Stubbing method implementation / return value](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#stubbing-method-implementation--return-value)
|
211
|
+
|
212
|
+
Again, there's only one true API form you can use. On the other hand,
|
213
|
+
since Muack is more strict than RR. Passing no arguments means you
|
214
|
+
really don't want any argument. Here we need to specify the argument
|
215
|
+
for Muack. The example should be changed to:
|
216
|
+
|
217
|
+
``` ruby
|
218
|
+
stub(object).foo(is_a(Fixnum), anything){ |age, count, &block|
|
219
|
+
raise 'hell' if age < 16
|
220
|
+
ret = block.call count
|
221
|
+
blue? ? ret : 'whatever'
|
222
|
+
}
|
223
|
+
```
|
224
|
+
|
225
|
+
#### [Stubbing method implementation based on argument expectation](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#stubbing-method-implementation-based-on-argument-expectation)
|
226
|
+
|
227
|
+
Here is exactly the same as RR.
|
228
|
+
|
229
|
+
``` ruby
|
230
|
+
stub(object).foo { 'bar' }
|
231
|
+
stub(object).foo(1, 2) { 'baz' }
|
232
|
+
object.foo #=> 'bar'
|
233
|
+
object.foo(1, 2) #=> 'baz'
|
234
|
+
```
|
235
|
+
|
236
|
+
#### [Stubbing method to yield given block](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#stubbing-method-to-yield-given-block)
|
237
|
+
|
238
|
+
Always use the block to pass whatever back.
|
239
|
+
|
240
|
+
``` ruby
|
241
|
+
stub(object).foo{ |&block| block.call(1, 2, 3) }
|
242
|
+
object.foo {|*args| args } # [1, 2, 3]
|
243
|
+
```
|
244
|
+
|
245
|
+
#### [Expecting method to be called with exact argument list](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-with-exact-argument-list)
|
246
|
+
|
247
|
+
Muack is strict, you always have to specify the argument list.
|
248
|
+
|
249
|
+
``` ruby
|
250
|
+
mock(object).foo(1, 2)
|
251
|
+
object.foo(1, 2) # ok
|
252
|
+
object.foo(3) # fails
|
253
|
+
```
|
254
|
+
|
255
|
+
Passing no arguments really means passing no arguments.
|
256
|
+
|
257
|
+
``` ruby
|
258
|
+
stub(object).foo
|
259
|
+
stub(object).foo(1, 2)
|
260
|
+
object.foo(1, 2) # ok
|
261
|
+
object.foo # ok
|
262
|
+
object.foo(3) # fails
|
263
|
+
```
|
264
|
+
|
265
|
+
#### [Expecting method to be called with any arguments](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-with-any-arguments)
|
266
|
+
|
267
|
+
Muack also provides `with_any_args` if we don't really care.
|
268
|
+
|
269
|
+
``` ruby
|
270
|
+
stub(object).foo.with_any_args
|
271
|
+
object.foo # ok
|
272
|
+
object.foo(1) # also ok
|
273
|
+
object.foo(1, 2) # also ok
|
274
|
+
# ... you get the idea
|
275
|
+
```
|
276
|
+
|
277
|
+
#### [Expecting method to be called with no arguments](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-with-no-arguments)
|
278
|
+
|
279
|
+
Just don't pass any argument :)
|
280
|
+
|
281
|
+
``` ruby
|
282
|
+
stub(object).foo
|
283
|
+
object.foo # ok
|
284
|
+
object.foo(1) # fails
|
285
|
+
```
|
286
|
+
|
287
|
+
#### [Expecting method to never be called](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-never-be-called)
|
288
|
+
|
289
|
+
Simply use `times(0)`.
|
290
|
+
|
291
|
+
``` ruby
|
292
|
+
mock(object).foo.times(0)
|
293
|
+
object.foo # fails
|
294
|
+
```
|
295
|
+
|
296
|
+
Multiple mock with different argument set is fine, too.
|
297
|
+
|
298
|
+
```
|
299
|
+
mock(object).foo(1, 2).times(0)
|
300
|
+
mock(object).foo(3, 4)
|
301
|
+
object.foo(3, 4) # ok
|
302
|
+
object.foo(1, 2) # fails
|
303
|
+
```
|
304
|
+
|
305
|
+
#### [Expecting method to be called only once](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-only-once)
|
306
|
+
|
307
|
+
By default, a mock only expects a call. Using `times(1)` is actually a no-op.
|
308
|
+
|
309
|
+
``` ruby
|
310
|
+
mock(object).foo.times(1)
|
311
|
+
object.foo
|
312
|
+
object.foo # fails
|
313
|
+
```
|
314
|
+
|
315
|
+
#### [Expecting method to called exact number of times](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-called-exact-number-of-times)
|
316
|
+
|
317
|
+
Times! Which is the same as RR.
|
318
|
+
|
319
|
+
``` ruby
|
320
|
+
mock(object).foo.times(3)
|
321
|
+
object.foo
|
322
|
+
object.foo
|
323
|
+
object.foo
|
324
|
+
object.foo # fails
|
325
|
+
```
|
326
|
+
|
327
|
+
Alternatively, you could also do this. It's exactly the same.
|
328
|
+
|
329
|
+
``` ruby
|
330
|
+
3.times{ mock(object).foo }
|
331
|
+
object.foo
|
332
|
+
object.foo
|
333
|
+
object.foo
|
334
|
+
object.foo # fails
|
335
|
+
```
|
336
|
+
|
337
|
+
#### [Expecting method to be called minimum number of times](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-minimum-number-of-times)
|
338
|
+
|
339
|
+
It's not supported in Muack, but we could emulate it somehow:
|
340
|
+
|
341
|
+
``` ruby
|
342
|
+
times = 0
|
343
|
+
stub(object).foo{ times += 1 }
|
344
|
+
object.foo
|
345
|
+
object.foo
|
346
|
+
raise "BOOM" if times <= 3
|
347
|
+
```
|
348
|
+
|
349
|
+
#### [Expecting method to be called maximum number of times](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-maximum-number-of-times)
|
350
|
+
|
351
|
+
|
352
|
+
It's not supported in Muack, but we could emulate it somehow:
|
353
|
+
|
354
|
+
``` ruby
|
355
|
+
times = 0
|
356
|
+
stub(object).foo{ times += 1; raise "BOOM" if times > 3 }
|
357
|
+
object.foo
|
358
|
+
object.foo
|
359
|
+
object.foo
|
360
|
+
object.foo
|
361
|
+
```
|
362
|
+
|
363
|
+
#### [Expecting method to be called any number of times](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#expecting-method-to-be-called-any-number-of-times)
|
364
|
+
|
365
|
+
Just use `stub`, which is exactly why it is designed.
|
366
|
+
|
367
|
+
``` ruby
|
368
|
+
stub(object).foo
|
369
|
+
object.foo
|
370
|
+
object.foo
|
371
|
+
object.foo
|
372
|
+
```
|
373
|
+
|
374
|
+
#### [Argument wildcard matchers](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#argument-wildcard-matchers)
|
375
|
+
|
376
|
+
`anything` is the same as RR.
|
377
|
+
|
378
|
+
``` ruby
|
379
|
+
mock(object).foobar(1, anything)
|
380
|
+
object.foobar(1, :my_symbol)
|
381
|
+
```
|
382
|
+
|
383
|
+
`is_a` is the same as RR.
|
384
|
+
|
385
|
+
``` ruby
|
386
|
+
mock(object).foobar(is_a(Time))
|
387
|
+
object.foobar(Time.now)
|
388
|
+
```
|
389
|
+
|
390
|
+
No numeric supports. Simply use `is_a(Numeric)`
|
391
|
+
|
392
|
+
``` ruby
|
393
|
+
mock(object).foobar(is_a(Numeric))
|
394
|
+
object.foobar(99)
|
395
|
+
```
|
396
|
+
|
397
|
+
No boolean supports. Pass a custom satisfy block for it:
|
398
|
+
|
399
|
+
``` ruby
|
400
|
+
mock(object).foobar(
|
401
|
+
satisfy{ |a| a.kind_of?(TrueClass) || a.kind_of?(FalseClass) })
|
402
|
+
object.foobar(false)
|
403
|
+
```
|
404
|
+
|
405
|
+
No duck_type supports. Pass a custom satisfy block for it:
|
406
|
+
|
407
|
+
``` ruby
|
408
|
+
mock(object).foobar(
|
409
|
+
satisfy{ |a| a.respond_to?(:walk) && a.respond_to?(:talk) })
|
410
|
+
arg = Object.new
|
411
|
+
def arg.walk; 'waddle'; end
|
412
|
+
def arg.talk; 'quack'; end
|
413
|
+
object.foobar(arg)
|
414
|
+
```
|
415
|
+
|
416
|
+
Don't pass ranges directly for ranges, use `within`. Or how do we tell
|
417
|
+
if we really want the argument to be a `Range` object?
|
418
|
+
|
419
|
+
``` ruby
|
420
|
+
mock(object).foobar(within(1..10))
|
421
|
+
object.foobar(5)
|
422
|
+
```
|
423
|
+
|
424
|
+
The same goes to regular expression. Use `match` instead.
|
425
|
+
|
426
|
+
``` ruby
|
427
|
+
mock(object).foobar(match(/on/))
|
428
|
+
object.foobar("ruby on rails")
|
429
|
+
```
|
430
|
+
|
431
|
+
`hash_including` is the same as RR.
|
432
|
+
|
433
|
+
``` ruby
|
434
|
+
mock(object).foobar(hash_including(:red => "#FF0000", :blue => "#0000FF"))
|
435
|
+
object.foobar({:red => "#FF0000", :blue => "#0000FF", :green => "#00FF00"})
|
436
|
+
```
|
437
|
+
|
438
|
+
`satisfy` is the same as RR.
|
439
|
+
|
440
|
+
``` ruby
|
441
|
+
mock(object).foobar(satisfy {|arg| arg.length == 2 })
|
442
|
+
object.foobar("xy")
|
443
|
+
```
|
444
|
+
|
445
|
+
#### [Writing your own argument matchers](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#writing-your-own-argument-matchers)
|
446
|
+
|
447
|
+
See [`lib/muack.rb`][muack.rb] and [`lib/muack/satisfy.rb`][satisfy.rb],
|
448
|
+
you would get the idea soon. Here's how `is_a` implemented.
|
449
|
+
|
450
|
+
``` ruby
|
451
|
+
module Muack::API
|
452
|
+
module_function
|
453
|
+
def is_a klass
|
454
|
+
Muack::IsA.new(klass)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
class Muack::IsA < Muack::Satisfy
|
459
|
+
def initialize klass
|
460
|
+
super lambda{ |actual_arg| actual_arg.kind_of?(klass) }, [klass]
|
461
|
+
end
|
462
|
+
end
|
463
|
+
```
|
464
|
+
|
465
|
+
[muack.rb]: https://github.com/godfat/muack/blob/master/lib/muack.rb
|
466
|
+
[satisfy.rb]: https://github.com/godfat/muack/blob/master/lib/muack/satisfy.rb
|
467
|
+
|
468
|
+
## USERS:
|
469
|
+
|
470
|
+
* [Rib][]
|
471
|
+
* [rest-core](https://github.com/cardinalblue/rest-core)
|
472
|
+
* [rest-more](https://github.com/cardinalblue/rest-more)
|
473
|
+
|
474
|
+
## CONTRIBUTORS:
|
475
|
+
|
476
|
+
* Lin Jen-Shin (@godfat)
|
477
|
+
|
478
|
+
## LICENSE:
|
479
|
+
|
480
|
+
Apache License 2.0
|
481
|
+
|
482
|
+
Copyright (c) 2013, Lin Jen-Shin (godfat)
|
483
|
+
|
484
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
485
|
+
you may not use this file except in compliance with the License.
|
486
|
+
You may obtain a copy of the License at
|
487
|
+
|
488
|
+
<http://www.apache.org/licenses/LICENSE-2.0>
|
489
|
+
|
490
|
+
Unless required by applicable law or agreed to in writing, software
|
491
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
492
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
493
|
+
See the License for the specific language governing permissions and
|
494
|
+
limitations under the License.
|