muack 0.5.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +42 -0
- data/README.md +49 -8
- data/lib/muack.rb +6 -10
- data/lib/muack/any_instance_of.rb +5 -1
- data/lib/muack/definition.rb +2 -1
- data/lib/muack/error.rb +18 -0
- data/lib/muack/mock.rb +40 -18
- data/lib/muack/modifier.rb +12 -1
- data/lib/muack/session.rb +7 -7
- data/lib/muack/spy.rb +23 -0
- data/lib/muack/stub.rb +5 -6
- data/lib/muack/version.rb +1 -1
- data/muack.gemspec +4 -3
- data/test/test_any_instance_of.rb +52 -13
- data/test/test_mock.rb +7 -7
- data/test/test_proxy.rb +28 -16
- data/test/test_satisfy.rb +6 -6
- data/test/test_stub.rb +92 -1
- metadata +4 -3
- data/lib/muack/proxy.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7727020cca0c41dfd846c0b7628aec71c2cbb59
|
4
|
+
data.tar.gz: 9fb966eb9e9e1dc65d8f0e938d2d0a619813f204
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 669fbb6e488468cf698bf28782e989f70a7fa82c447b91ef4efdc62892add2bf828d9604d682fbe4b13780cf1599017fbfff22f5d7fa8bbb43c0603b7e5b5d97
|
7
|
+
data.tar.gz: b6465725ab6109aeead47a3bba111df9095434ec557017ad0141c1ff441e51054504f4217d19fc6b9e1ad2ef2e86e6fdd8cc59cc3568d2498b89bdd30e257dd4
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,47 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## Muack 0.7.0 -- 2013-06-27
|
4
|
+
|
5
|
+
### Incompatible changes
|
6
|
+
|
7
|
+
* Now instead of using mock_proxy, we use `proxy` as a modifier. That says
|
8
|
+
mock_proxy and stub_proxy no longer existed. like this:
|
9
|
+
|
10
|
+
``` ruby
|
11
|
+
mock(object).to_s.proxy
|
12
|
+
stub(object).to_s.proxy
|
13
|
+
```
|
14
|
+
|
15
|
+
We change this due to the introduction of spies.
|
16
|
+
|
17
|
+
### Enhancement
|
18
|
+
|
19
|
+
* We have spies support now. Here's an example:
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
subject = Object.new
|
23
|
+
stub(subject).foo(1)
|
24
|
+
subject.foo(1)
|
25
|
+
|
26
|
+
spy(subject).foo(1)
|
27
|
+
spy(subject).bar # This doesn't verify immediately.
|
28
|
+
Muack.verify # This fails, saying `bar` was never called.
|
29
|
+
```
|
30
|
+
|
31
|
+
* It would now raise a `StubHasNoTimes` exception if you tried to set times
|
32
|
+
on stubs, which has no meanings in Muack. Use `mock` or `spy` instead if
|
33
|
+
you need to specify times.
|
34
|
+
|
35
|
+
* Muack.reset and Muack.verify is now thread-safe.
|
36
|
+
You can run test cases concurrently now.
|
37
|
+
|
38
|
+
* AnyInstanceOf now has a more readable inspect.
|
39
|
+
* Improved various error messages. e.g. CannotFindInjectionName.
|
40
|
+
* You can now set ENV['MUACK_RECURSION_LEVEL'] to raise the limit
|
41
|
+
to find a new method name when we're injecting a method. Normally
|
42
|
+
this should not happen, and it could be a bug in Muack. But instead of
|
43
|
+
putting a magic number 9 out there as before, this might be better.
|
44
|
+
|
3
45
|
## Muack 0.5.2 -- 2013-06-26
|
4
46
|
|
5
47
|
* Add `returns` modifier which you can pass the return values if passing
|
data/README.md
CHANGED
@@ -101,27 +101,47 @@ User.find('42').times(0)
|
|
101
101
|
User.find('42') # raises a Muack::Unexpected
|
102
102
|
```
|
103
103
|
|
104
|
-
#### [
|
104
|
+
#### [proxy](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#mockproxy)
|
105
105
|
|
106
|
-
|
107
|
-
|
106
|
+
Instead of calling `proxy` immediately after calling `mock`, we put
|
107
|
+
`proxy` the last because it's a method from `Muack::Modifier`.
|
108
108
|
|
109
109
|
``` ruby
|
110
110
|
view = controller.template
|
111
|
-
|
112
|
-
|
111
|
+
mock(view).render(:partial => "right_navigation").proxy
|
112
|
+
mock(view).render(:partial => "user_info") do |html|
|
113
|
+
html.should include("John Doe")
|
114
|
+
"Different html"
|
115
|
+
end.proxy
|
116
|
+
```
|
117
|
+
|
118
|
+
If you feel it is weird to put proxy the last, you can also use
|
119
|
+
`returns` modifier to put the block last as this:
|
120
|
+
|
121
|
+
``` ruby
|
122
|
+
view = controller.template
|
123
|
+
mock(view).render(:partial => "right_navigation").proxy
|
124
|
+
mock(view).render(:partial => "user_info").proxy.returns do |html|
|
113
125
|
html.should include("John Doe")
|
114
126
|
"Different html"
|
115
127
|
end
|
116
128
|
```
|
117
129
|
|
118
|
-
|
130
|
+
The same goes to `stub`.
|
119
131
|
|
120
|
-
|
132
|
+
``` ruby
|
133
|
+
view = controller.template
|
134
|
+
stub(view).render(:partial => "user_info") do |html|
|
135
|
+
html.should include("Joe Smith")
|
136
|
+
html
|
137
|
+
end.proxy
|
138
|
+
```
|
139
|
+
|
140
|
+
Or use `returns`:
|
121
141
|
|
122
142
|
``` ruby
|
123
143
|
view = controller.template
|
124
|
-
|
144
|
+
stub(view).render(:partial => "user_info").proxy.returns do |html|
|
125
145
|
html.should include("Joe Smith")
|
126
146
|
html
|
127
147
|
end
|
@@ -141,6 +161,27 @@ any_instance_of(User) do |u|
|
|
141
161
|
end
|
142
162
|
```
|
143
163
|
|
164
|
+
#### [Spies](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#spies)
|
165
|
+
|
166
|
+
We don't try to provide different methods for different testing framework,
|
167
|
+
so that we don't have to create so many testing framework adapters, and
|
168
|
+
try to be smart to find the correct adapter. There are simply too many
|
169
|
+
testing frameworks out there. Ruby's built-in test/unit and minitest have
|
170
|
+
a lot of different versions, so does rspec.
|
171
|
+
|
172
|
+
Here we just try to do it the Muack's way:
|
173
|
+
|
174
|
+
|
175
|
+
``` ruby
|
176
|
+
subject = Object.new
|
177
|
+
stub(subject).foo(1)
|
178
|
+
subject.foo(1)
|
179
|
+
|
180
|
+
spy(subject).foo(1)
|
181
|
+
spy(subject).bar # This doesn't verify immediately.
|
182
|
+
Muack.verify # This fails, saying `bar` was never called.
|
183
|
+
```
|
184
|
+
|
144
185
|
#### [Block form](https://github.com/rr/rr/blob/e4b4907fd0488738affb4dab8ce88cbe9fa6580e/doc/03_api_overview.md#block-syntax)
|
145
186
|
|
146
187
|
Block form is also supported. However we don't support `instance_eval` form.
|
data/lib/muack.rb
CHANGED
@@ -10,12 +10,13 @@ module Muack
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.session
|
13
|
-
|
13
|
+
Thread.current[:muack_session] ||= Muack::Session.new
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.reset
|
17
|
-
|
18
|
-
|
17
|
+
session = Thread.current[:muack_session]
|
18
|
+
session && session.reset
|
19
|
+
Thread.current[:muack_session] = nil
|
19
20
|
end
|
20
21
|
|
21
22
|
module API
|
@@ -30,13 +31,8 @@ module Muack
|
|
30
31
|
if block_given? then yield(ret) else ret end
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
ret = Muack.session.
|
35
|
-
if block_given? then yield(ret) else ret end
|
36
|
-
end
|
37
|
-
|
38
|
-
def stub_proxy obj=Object.new
|
39
|
-
ret = Muack.session.stub_proxy(obj)
|
34
|
+
def spy obj
|
35
|
+
ret = Muack.session.spy(obj)
|
40
36
|
if block_given? then yield(ret) else ret end
|
41
37
|
end
|
42
38
|
|
data/lib/muack/definition.rb
CHANGED
data/lib/muack/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module Muack
|
3
|
+
Error = Class.new(NotImplementedError)
|
4
|
+
class CannotFindInjectionName < Error
|
5
|
+
def initialize t, msg
|
6
|
+
super "\nCan't find a new method name for :#{msg}, tried #{t} times." \
|
7
|
+
"\nSet ENV['MUACK_RECURSION_LEVEL'] to raise this limit."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class StubHasNoTimes < Error
|
12
|
+
def initialize obj, defi, times
|
13
|
+
super "\nUse mocks if you want to specify times.\ne.g. " \
|
14
|
+
"mock(#{obj.inspect}).#{defi.msg}(#{defi.args.join(', ')})" \
|
15
|
+
".times(#{times})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/muack/mock.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'muack/definition'
|
3
3
|
require 'muack/modifier'
|
4
4
|
require 'muack/failure'
|
5
|
+
require 'muack/error'
|
5
6
|
|
6
7
|
module Muack
|
7
8
|
class Mock < BasicObject
|
@@ -16,7 +17,7 @@ module Muack
|
|
16
17
|
|
17
18
|
# Public API: Bacon needs this, or we often ended up with stack overflow
|
18
19
|
def inspect
|
19
|
-
"
|
20
|
+
"Muack::API.#{__mock_class.name[/\w+$/].downcase}(#{object.inspect})"
|
20
21
|
end
|
21
22
|
|
22
23
|
# Public API: Define mocked method
|
@@ -41,12 +42,17 @@ module Muack
|
|
41
42
|
__mock_defis[defi.msg].pop
|
42
43
|
end
|
43
44
|
|
45
|
+
# used for Muack::Modifier#times to determine if it's a mock or not
|
46
|
+
def __mock_class
|
47
|
+
(class << self; self; end).superclass
|
48
|
+
end
|
49
|
+
|
44
50
|
# used for mocked object to dispatch mocked method
|
45
|
-
def __mock_dispatch msg, actual_args
|
51
|
+
def __mock_dispatch msg, actual_args
|
46
52
|
if defi = __mock_defis[msg].shift
|
47
53
|
__mock_disps_push(defi)
|
48
54
|
if __mock_check_args(defi.args, actual_args)
|
49
|
-
|
55
|
+
defi
|
50
56
|
else
|
51
57
|
Mock.__send__(:raise, # Wrong argument
|
52
58
|
Unexpected.new(object, [defi], msg, actual_args))
|
@@ -63,6 +69,25 @@ module Muack
|
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
72
|
+
# used for mocked object to dispatch mocked method
|
73
|
+
def __mock_dispatch_call disp, actual_args, actual_block
|
74
|
+
if disp.proxy
|
75
|
+
value = yield # need the original context for proxy or AnyInstanceOf
|
76
|
+
if disp.block
|
77
|
+
disp.block.call(value)
|
78
|
+
else
|
79
|
+
value
|
80
|
+
end
|
81
|
+
elsif block = disp.block
|
82
|
+
arity = block.arity
|
83
|
+
if arity < 0
|
84
|
+
block.call(*actual_args , &actual_block)
|
85
|
+
else
|
86
|
+
block.call(*actual_args.first(arity), &actual_block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
66
91
|
# used for Muack::Session#verify
|
67
92
|
def __mock_verify
|
68
93
|
__mock_defis.values.all?(&:empty?) || begin
|
@@ -94,7 +119,7 @@ module Muack
|
|
94
119
|
private
|
95
120
|
def __mock_inject_method defi
|
96
121
|
__mock_injected[defi.msg] = defi
|
97
|
-
target = object.singleton_class
|
122
|
+
target = object.singleton_class # would be the class in AnyInstanceOf
|
98
123
|
Mock.store_original_method(target, defi)
|
99
124
|
__mock_inject_mock_method(target, defi)
|
100
125
|
end
|
@@ -108,8 +133,9 @@ module Muack
|
|
108
133
|
end
|
109
134
|
|
110
135
|
def self.find_new_name klass, message, level=0
|
111
|
-
|
112
|
-
level
|
136
|
+
if level >= (::ENV['MUACK_RECURSION_LEVEL'] || 9).to_i
|
137
|
+
raise CannotFindInjectionName.new(level+1, message)
|
138
|
+
end
|
113
139
|
|
114
140
|
new_name = "__muack_mock_#{level}_#{message}".to_sym
|
115
141
|
if klass.instance_methods(false).include?(new_name)
|
@@ -122,21 +148,17 @@ module Muack
|
|
122
148
|
def __mock_inject_mock_method target, defi
|
123
149
|
mock = self # remember the context
|
124
150
|
target.__send__(:define_method, defi.msg){|*actual_args, &actual_block|
|
125
|
-
mock.__mock_dispatch(defi.msg, actual_args
|
151
|
+
disp = mock.__mock_dispatch(defi.msg, actual_args)
|
152
|
+
mock.__mock_dispatch_call(disp, actual_args, actual_block){
|
153
|
+
if disp.original_method
|
154
|
+
__send__(disp.original_method, *actual_args, &actual_block)
|
155
|
+
else
|
156
|
+
super(*actual_args, &actual_block)
|
157
|
+
end
|
158
|
+
}
|
126
159
|
}
|
127
160
|
end
|
128
161
|
|
129
|
-
def __mock_block_call defi, actual_args, actual_block
|
130
|
-
if block = defi.block
|
131
|
-
arity = block.arity
|
132
|
-
if arity < 0
|
133
|
-
block.call(*actual_args , &actual_block)
|
134
|
-
else
|
135
|
-
block.call(*actual_args.first(arity), &actual_block)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
162
|
def __mock_check_args expected_args, actual_args
|
141
163
|
if expected_args == [WithAnyArgs]
|
142
164
|
true
|
data/lib/muack/modifier.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
require 'muack/
|
2
|
+
require 'muack/error'
|
3
3
|
|
4
4
|
module Muack
|
5
5
|
class Modifier < Struct.new(:mock, :defi)
|
@@ -12,10 +12,21 @@ module Muack
|
|
12
12
|
# Public API
|
13
13
|
def returns val=nil, &block
|
14
14
|
defi.block = block || lambda{ val }
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Public API
|
19
|
+
def proxy
|
20
|
+
defi.proxy = true
|
21
|
+
self
|
15
22
|
end
|
16
23
|
|
17
24
|
# Public API
|
18
25
|
def times number
|
26
|
+
if mock.__mock_class == Stub
|
27
|
+
raise StubHasNoTimes.new(object, defi, number)
|
28
|
+
end
|
29
|
+
|
19
30
|
if number >= 1
|
20
31
|
(number - 1).times{ mock.__mock_defis_push(defi) }
|
21
32
|
elsif number == 0
|
data/lib/muack/session.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
|
2
2
|
require 'muack/mock'
|
3
3
|
require 'muack/stub'
|
4
|
-
require 'muack/
|
4
|
+
require 'muack/spy'
|
5
5
|
require 'muack/any_instance_of'
|
6
6
|
|
7
7
|
module Muack
|
8
8
|
class Session < Hash
|
9
|
-
def mock
|
10
|
-
def stub
|
11
|
-
def
|
12
|
-
def stub_proxy obj; self["sp #{obj.__id__}"] ||= StubProxy.new(obj); end
|
9
|
+
def mock obj; self["mk #{obj.__id__}"] ||= Mock.new(obj) ; end
|
10
|
+
def stub obj; self["sb #{obj.__id__}"] ||= Stub.new(obj) ; end
|
11
|
+
def spy obj; self["sy #{obj.__id__}"] ||= Spy .new(stub(obj)); end
|
13
12
|
|
14
|
-
def any_instance_of
|
15
|
-
(@
|
13
|
+
def any_instance_of kls
|
14
|
+
(@others ||= {})["ai #{kls.__id__}"] ||= AnyInstanceOf.new(kls)
|
16
15
|
end
|
17
16
|
|
18
17
|
def verify
|
@@ -20,6 +19,7 @@ module Muack
|
|
20
19
|
end
|
21
20
|
|
22
21
|
def reset
|
22
|
+
instance_variable_defined?(:@others) && @others.clear
|
23
23
|
each_value(&:__mock_reset)
|
24
24
|
clear
|
25
25
|
end
|
data/lib/muack/spy.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require 'muack/mock'
|
3
|
+
|
4
|
+
module Muack
|
5
|
+
class Spy < Mock
|
6
|
+
def initialize stub
|
7
|
+
super(stub.object)
|
8
|
+
@secret = stub.__mock_disps.values.flatten # steal disps
|
9
|
+
end
|
10
|
+
|
11
|
+
# used for Muack::Session#verify
|
12
|
+
def __mock_verify
|
13
|
+
@secret.each{ |defi| __mock_dispatch(defi.msg, defi.args) }
|
14
|
+
super # simulate dispatching before passing to mock to verify
|
15
|
+
end
|
16
|
+
|
17
|
+
# used for Muack::Session#reset, but spies never leave any track
|
18
|
+
def __mock_reset; end
|
19
|
+
|
20
|
+
private
|
21
|
+
def __mock_inject_method defi; end # spies don't leave any track
|
22
|
+
end
|
23
|
+
end
|
data/lib/muack/stub.rb
CHANGED
@@ -7,12 +7,11 @@ module Muack
|
|
7
7
|
def __mock_verify; true; end
|
8
8
|
|
9
9
|
# used for mocked object to dispatch mocked method
|
10
|
-
def __mock_dispatch msg, actual_args
|
11
|
-
defi = __mock_defis[msg].find{ |d|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
__mock_block_call(defi, actual_args, actual_block)
|
10
|
+
def __mock_dispatch msg, actual_args
|
11
|
+
if defi = __mock_defis[msg].find{ |d|
|
12
|
+
__mock_check_args(d.args, actual_args) }
|
13
|
+
__mock_disps_push(defi) # our spies are interested in this
|
14
|
+
defi
|
16
15
|
else
|
17
16
|
Mock.__send__(:raise, # Wrong argument
|
18
17
|
Unexpected.new(object, __mock_defis[msg], msg, actual_args))
|
data/lib/muack/version.rb
CHANGED
data/muack.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "muack"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.7.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Lin Jen-Shin (godfat)"]
|
9
|
-
s.date = "2013-06-
|
9
|
+
s.date = "2013-06-27"
|
10
10
|
s.description = "Muack -- Yet another mocking library.\n\nBasically it's an [RR][] clone, but much faster under heavy use.\nIt's 32x times faster (750s vs 23s) for running [Rib][] tests.\n\n[RR]: https://github.com/rr/rr\n[Rib]: https://github.com/godfat/rib"
|
11
11
|
s.email = ["godfat (XD) godfat.org"]
|
12
12
|
s.files = [
|
@@ -21,12 +21,13 @@ Gem::Specification.new do |s|
|
|
21
21
|
"lib/muack.rb",
|
22
22
|
"lib/muack/any_instance_of.rb",
|
23
23
|
"lib/muack/definition.rb",
|
24
|
+
"lib/muack/error.rb",
|
24
25
|
"lib/muack/failure.rb",
|
25
26
|
"lib/muack/mock.rb",
|
26
27
|
"lib/muack/modifier.rb",
|
27
|
-
"lib/muack/proxy.rb",
|
28
28
|
"lib/muack/satisfy.rb",
|
29
29
|
"lib/muack/session.rb",
|
30
|
+
"lib/muack/spy.rb",
|
30
31
|
"lib/muack/stub.rb",
|
31
32
|
"lib/muack/test.rb",
|
32
33
|
"lib/muack/version.rb",
|
@@ -2,8 +2,9 @@
|
|
2
2
|
require 'muack/test'
|
3
3
|
|
4
4
|
describe Muack::AnyInstanceOf do
|
5
|
+
klass = Class.new{ def f; 0; end }
|
6
|
+
|
5
7
|
should 'mock any_instance_of' do
|
6
|
-
klass = Class.new
|
7
8
|
any_instance_of(klass){ |instance| mock(instance).say{ true } }
|
8
9
|
obj = klass.new
|
9
10
|
obj.say .should.eq true
|
@@ -13,17 +14,15 @@ describe Muack::AnyInstanceOf do
|
|
13
14
|
end
|
14
15
|
|
15
16
|
should 'proxy any_instance_of' do
|
16
|
-
klass
|
17
|
-
any_instance_of(klass){ |instance| mock_proxy(instance).f }
|
17
|
+
any_instance_of(klass){ |instance| mock(instance).f.proxy }
|
18
18
|
obj = klass.new
|
19
|
-
obj.f .should.eq
|
19
|
+
obj.f .should.eq 0
|
20
20
|
Muack.verify.should.eq true
|
21
|
-
obj.f .should.eq
|
21
|
+
obj.f .should.eq 0
|
22
22
|
end
|
23
23
|
|
24
24
|
should 'proxy any_instance_of with a block' do
|
25
|
-
klass
|
26
|
-
any_instance_of(klass){ |instance| mock_proxy(instance).f{ |i| i+1 } }
|
25
|
+
any_instance_of(klass){ |instance| mock(instance).f{ |i| i+1 }.proxy }
|
27
26
|
obj = klass.new
|
28
27
|
obj.f .should.eq 1
|
29
28
|
Muack.verify.should.eq true
|
@@ -31,9 +30,8 @@ describe Muack::AnyInstanceOf do
|
|
31
30
|
end
|
32
31
|
|
33
32
|
should 'proxy with multiple any_instance_of call' do
|
34
|
-
klass
|
35
|
-
any_instance_of(klass){ |instance|
|
36
|
-
any_instance_of(klass){ |instance| mock_proxy(instance).f{ |i| i+2 } }
|
33
|
+
any_instance_of(klass){ |instance| mock(instance).f{ |i| i+1 }.proxy }
|
34
|
+
any_instance_of(klass){ |instance| mock(instance).f{ |i| i+2 }.proxy }
|
37
35
|
obj = klass.new
|
38
36
|
obj.f.should.eq 1
|
39
37
|
obj.f.should.eq 2
|
@@ -42,13 +40,54 @@ describe Muack::AnyInstanceOf do
|
|
42
40
|
end
|
43
41
|
|
44
42
|
should 'mock with multiple any_instance_of call' do
|
45
|
-
klass = Class.new{ def f; 0; end }
|
46
43
|
any_instance_of(klass){ |inst| mock(inst).f(is_a(Fixnum)){ |i| i+1 } }
|
47
44
|
any_instance_of(klass){ |inst| mock(inst).f(is_a(Fixnum)){ |i| i+2 } }
|
48
45
|
obj = klass.new
|
49
|
-
obj.f(
|
50
|
-
obj.f(
|
46
|
+
obj.f(2).should.eq 3
|
47
|
+
obj.f(2).should.eq 4
|
48
|
+
Muack.verify.should.eq true
|
49
|
+
obj.f.should.eq 0
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'stub proxy with any_instance_of and spy' do
|
53
|
+
any_instance_of(klass){ |inst| stub(inst).f{ |i| i+3 }.proxy }
|
54
|
+
obj = klass.new
|
55
|
+
obj.f.should.eq 3
|
56
|
+
obj.f.should.eq 3
|
57
|
+
spy(any_instance_of(klass)).f.times(2)
|
51
58
|
Muack.verify.should.eq true
|
52
59
|
obj.f.should.eq 0
|
53
60
|
end
|
61
|
+
|
62
|
+
should 'stub with any_instance_of and spy under satisfied' do
|
63
|
+
any_instance_of(klass){ |inst| stub(inst).f{ 5 } }
|
64
|
+
obj = klass.new
|
65
|
+
obj.f.should.eq 5
|
66
|
+
spy(any_instance_of(klass)).f.times(2)
|
67
|
+
begin
|
68
|
+
Muack.verify
|
69
|
+
rescue Muack::Expected => e
|
70
|
+
expected = /Muack::API\.any_instance_of\(.+?\)\.f\(\)/
|
71
|
+
e.expected .should =~ expected
|
72
|
+
e.expected_times.should.eq 2
|
73
|
+
e.actual_times .should.eq 1
|
74
|
+
end
|
75
|
+
obj.f.should.eq 0
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'stub with any_instance_of and spy over satisfied' do
|
79
|
+
any_instance_of(klass){ |inst| stub(inst).f{ 2 } }
|
80
|
+
obj = klass.new
|
81
|
+
2.times{ obj.f.should.eq 2 }
|
82
|
+
spy(any_instance_of(klass)).f
|
83
|
+
begin
|
84
|
+
Muack.verify
|
85
|
+
rescue Muack::Expected => e
|
86
|
+
expected = /Muack::API\.any_instance_of\(.+?\)\.f\(\)/
|
87
|
+
e.expected .should =~ expected
|
88
|
+
e.expected_times.should.eq 1
|
89
|
+
e.actual_times .should.eq 2
|
90
|
+
end
|
91
|
+
obj.f.should.eq 0
|
92
|
+
end
|
54
93
|
end
|
data/test/test_mock.rb
CHANGED
@@ -8,6 +8,10 @@ describe Muack::Mock do
|
|
8
8
|
Muack::EnsureReset.call
|
9
9
|
end
|
10
10
|
|
11
|
+
should 'inspect' do
|
12
|
+
mock(Obj).inspect.should.eq "Muack::API.mock(obj)"
|
13
|
+
end
|
14
|
+
|
11
15
|
should 'mock with regular method' do
|
12
16
|
mock(Obj).say(true){ 'boo' }
|
13
17
|
Obj.say(true).should.eq 'boo'
|
@@ -58,10 +62,6 @@ describe Muack::Mock do
|
|
58
62
|
mock.say{1}.object.say.should.eq 1
|
59
63
|
end
|
60
64
|
|
61
|
-
should 'inspect' do
|
62
|
-
mock(Obj).inspect.should.eq "#<Muack::Mock object=obj>"
|
63
|
-
end
|
64
|
-
|
65
65
|
should 'mock and call, mock and call' do
|
66
66
|
mock(Obj).say{0}
|
67
67
|
Obj.say.should.eq 0
|
@@ -94,7 +94,7 @@ describe Muack::Mock do
|
|
94
94
|
Muack::EnsureReset.call
|
95
95
|
end
|
96
96
|
|
97
|
-
should 'raise
|
97
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
98
98
|
mock(Obj).say(true){ 'boo' }
|
99
99
|
begin
|
100
100
|
Obj.say(false)
|
@@ -144,7 +144,7 @@ describe Muack::Mock do
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
-
should 'raise
|
147
|
+
should 'raise Unexpected when calling with diff sig' do
|
148
148
|
mock(Obj).say(true){1}
|
149
149
|
Obj.say(true).should.eq 1
|
150
150
|
begin
|
@@ -157,7 +157,7 @@ describe Muack::Mock do
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
should 'raise
|
160
|
+
should 'raise Expected error if mock methods not called' do
|
161
161
|
mock(Obj).say(true){ 'boo' }
|
162
162
|
begin
|
163
163
|
Muack.verify
|
data/test/test_proxy.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'muack/test'
|
3
3
|
|
4
|
-
describe Muack::
|
4
|
+
describe Muack::Mock do
|
5
5
|
describe 'Muack.verify==true' do
|
6
6
|
after do
|
7
7
|
Muack.verify.should.eq true
|
@@ -9,48 +9,60 @@ describe Muack::Proxy do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
should 'proxy with regular method' do
|
12
|
-
|
12
|
+
mock(Str).reverse.proxy
|
13
13
|
Str.reverse.should.eq 'ooM'
|
14
14
|
end
|
15
15
|
|
16
16
|
should 'proxy multiple times' do
|
17
|
-
2.times{
|
17
|
+
2.times{ mock(Str).reverse.proxy }
|
18
18
|
2.times{ Str.reverse.should.eq 'ooM' }
|
19
19
|
end
|
20
20
|
|
21
21
|
should 'proxy multiple times with super method' do
|
22
|
-
2.times{
|
22
|
+
2.times{ mock(Str).class.proxy }
|
23
23
|
2.times{ Str.class.should.eq String }
|
24
24
|
end
|
25
25
|
|
26
|
+
should 'return modifier itself for any modifier methods' do
|
27
|
+
mock(Str).to_s.proxy.returns{ |s| s.reverse }.times(2).
|
28
|
+
with_any_args.with_any_args
|
29
|
+
2.times{ Str.to_s.should.eq 'ooM' }
|
30
|
+
end
|
31
|
+
|
26
32
|
should 'proxy and call the block' do
|
27
|
-
|
33
|
+
mock(Obj).method_missing(:inspect){ |str| str.reverse }.proxy
|
28
34
|
Obj.inspect.should.eq 'jbo'
|
29
35
|
end
|
30
36
|
|
31
37
|
should 'proxy and call the block with super' do
|
32
|
-
|
38
|
+
mock(Str).class{ |k| k.name.reverse }.proxy
|
33
39
|
Str.class.should.eq 'gnirtS'
|
34
40
|
end
|
35
41
|
|
36
|
-
should '
|
37
|
-
|
42
|
+
should 'mock proxy and call, mock proxy and call' do
|
43
|
+
mock(Obj).class{ |k| k.name.reverse }.proxy
|
38
44
|
Obj.class.should.eq 'tcejbO'
|
39
|
-
|
45
|
+
mock(Obj).class{ |k| k.name.upcase }.proxy
|
40
46
|
Obj.class.should.eq 'OBJECT'
|
41
47
|
end
|
42
48
|
|
43
|
-
should '
|
44
|
-
|
49
|
+
should 'stub proxy and call, stub proxy and call' do
|
50
|
+
stub(Obj).kind_of?(Object){ |b| !b }.proxy
|
45
51
|
Obj.kind_of?(Object).should.eq false
|
46
|
-
|
52
|
+
stub(Obj).kind_of?(String){ |b| b.to_s }.proxy
|
47
53
|
Obj.kind_of?(String).should.eq 'false'
|
48
54
|
end
|
49
55
|
|
50
|
-
should '
|
51
|
-
|
56
|
+
should 'stub proxy with any times' do
|
57
|
+
stub(Obj).class{ |k| k.name.downcase }.proxy
|
52
58
|
3.times{ Obj.class.should.eq 'object' }
|
53
59
|
end
|
60
|
+
|
61
|
+
should 'stub proxy and spy' do
|
62
|
+
stub(Obj).class{ |k| k.name.downcase }.proxy
|
63
|
+
Obj.class.should.eq 'object'
|
64
|
+
spy(Obj).class
|
65
|
+
end
|
54
66
|
end
|
55
67
|
|
56
68
|
describe 'Muack.verify==false' do
|
@@ -59,8 +71,8 @@ describe Muack::Proxy do
|
|
59
71
|
Muack::EnsureReset.call
|
60
72
|
end
|
61
73
|
|
62
|
-
should 'raise
|
63
|
-
|
74
|
+
should 'raise Expected error if passing unexpected argument' do
|
75
|
+
mock(Str).reverse.proxy
|
64
76
|
Str.reverse.should.eq 'ooM'
|
65
77
|
begin
|
66
78
|
Str.reverse
|
data/test/test_satisfy.rb
CHANGED
@@ -17,7 +17,7 @@ describe Muack::Satisfy do
|
|
17
17
|
Muack::EnsureReset.call
|
18
18
|
end
|
19
19
|
|
20
|
-
should 'raise
|
20
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
21
21
|
mock(Obj).say(is_a(Array)){ 'boo' }
|
22
22
|
begin
|
23
23
|
Obj.say(false)
|
@@ -53,7 +53,7 @@ describe Muack::Satisfy do
|
|
53
53
|
Muack::EnsureReset.call
|
54
54
|
end
|
55
55
|
|
56
|
-
should 'raise
|
56
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
57
57
|
mock(Obj).say(anything){ 'boo' }
|
58
58
|
begin
|
59
59
|
Obj.say(6, 7)
|
@@ -84,7 +84,7 @@ describe Muack::Satisfy do
|
|
84
84
|
Muack::EnsureReset.call
|
85
85
|
end
|
86
86
|
|
87
|
-
should 'raise
|
87
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
88
88
|
mock(Obj).say(match(/\w/)){ 'boo' }
|
89
89
|
begin
|
90
90
|
Obj.say('!')
|
@@ -115,7 +115,7 @@ describe Muack::Satisfy do
|
|
115
115
|
Muack::EnsureReset.call
|
116
116
|
end
|
117
117
|
|
118
|
-
should 'raise
|
118
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
119
119
|
mock(Obj).say(hash_including(:b => 2)){ 'boo' }
|
120
120
|
begin
|
121
121
|
Obj.say(:a => 1)
|
@@ -151,7 +151,7 @@ describe Muack::Satisfy do
|
|
151
151
|
Muack::EnsureReset.call
|
152
152
|
end
|
153
153
|
|
154
|
-
should 'raise
|
154
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
155
155
|
mock(Obj).say(within(0..5)){ 'boo' }
|
156
156
|
begin
|
157
157
|
Obj.say(6)
|
@@ -182,7 +182,7 @@ describe Muack::Satisfy do
|
|
182
182
|
Muack::EnsureReset.call
|
183
183
|
end
|
184
184
|
|
185
|
-
should 'raise
|
185
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
186
186
|
mock(Obj).say(satisfy{ |arg| arg % 2 == 0 }){ 'boo' }
|
187
187
|
begin
|
188
188
|
Obj.say(1)
|
data/test/test_stub.rb
CHANGED
@@ -2,12 +2,24 @@
|
|
2
2
|
require 'muack/test'
|
3
3
|
|
4
4
|
describe Muack::Stub do
|
5
|
+
should 'raise StubHasNoTimes with stub(obj).f.times(0)' do
|
6
|
+
lambda{ stub(Obj).f.times(0) }.should.raise(Muack::StubHasNoTimes)
|
7
|
+
end
|
8
|
+
|
5
9
|
describe 'Muack.verify==true' do
|
6
10
|
after do
|
7
11
|
Muack.verify.should.eq true
|
8
12
|
Muack::EnsureReset.call
|
9
13
|
end
|
10
14
|
|
15
|
+
should 'inspect' do
|
16
|
+
stub(Obj).inspect.should.eq "Muack::API.stub(obj)"
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'inspect' do
|
20
|
+
spy( Obj).inspect.should.eq "Muack::API.spy(obj)"
|
21
|
+
end
|
22
|
+
|
11
23
|
should 'stub with regular method' do
|
12
24
|
stub(Obj).say{ 'goo' }
|
13
25
|
3.times{ Obj.say.should.eq 'goo' }
|
@@ -26,6 +38,24 @@ describe Muack::Stub do
|
|
26
38
|
Obj.saya.should.eq 1
|
27
39
|
Obj.say .should.eq 0
|
28
40
|
end
|
41
|
+
|
42
|
+
should 'work with spy' do
|
43
|
+
stub(Obj).say{0}
|
44
|
+
Obj.say.should.eq 0
|
45
|
+
spy(Obj).say
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'work with spy twice' do
|
49
|
+
stub(Obj).say
|
50
|
+
2.times{ Obj.say.should.eq nil }
|
51
|
+
spy(Obj).say.times(2)
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'work with spy spy' do
|
55
|
+
stub(Obj).say
|
56
|
+
2.times{ Obj.say.should.eq nil }
|
57
|
+
2.times{ spy(Obj).say }
|
58
|
+
end
|
29
59
|
end
|
30
60
|
|
31
61
|
describe 'Muack.verify==false' do
|
@@ -34,7 +64,7 @@ describe Muack::Stub do
|
|
34
64
|
Muack::EnsureReset.call
|
35
65
|
end
|
36
66
|
|
37
|
-
should 'raise
|
67
|
+
should 'raise Unexpected error if passing unexpected argument' do
|
38
68
|
stub(Obj).say(true){ 'boo' }
|
39
69
|
begin
|
40
70
|
Obj.say(false)
|
@@ -58,5 +88,66 @@ describe Muack::Stub do
|
|
58
88
|
e.message .should.eq "\nExpected: #{e.expected}\n but was: #{e.was}"
|
59
89
|
end
|
60
90
|
end
|
91
|
+
|
92
|
+
should 'raise Expected if the spy is not satisfied' do
|
93
|
+
stub(Obj).say
|
94
|
+
spy( Obj).say
|
95
|
+
begin
|
96
|
+
Muack.verify
|
97
|
+
'never'.should.eq 'reach'
|
98
|
+
rescue Muack::Expected => e
|
99
|
+
e.expected .should.eq 'obj.say()'
|
100
|
+
e.expected_times.should.eq 1
|
101
|
+
e.actual_times .should.eq 0
|
102
|
+
e.message .should.eq "\nExpected: obj.say()\n " \
|
103
|
+
"called 1 times\n but was 0 times."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
should 'raise Expected if the spy is not satisfied enough' do
|
108
|
+
stub(Obj).say
|
109
|
+
Obj.say
|
110
|
+
spy( Obj).say(0)
|
111
|
+
begin
|
112
|
+
Muack.verify
|
113
|
+
'never'.should.eq 'reach'
|
114
|
+
rescue Muack::Unexpected => e
|
115
|
+
e.expected.should.eq "obj.say(0)"
|
116
|
+
e.was .should.eq 'obj.say()'
|
117
|
+
e.message .should.eq "\nExpected: #{e.expected}\n but was: #{e.was}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
should 'show correct times for under satisfaction' do
|
122
|
+
stub(Obj).say
|
123
|
+
2.times{ Obj.say }
|
124
|
+
spy( Obj).say.times(3)
|
125
|
+
begin
|
126
|
+
Muack.verify
|
127
|
+
'never'.should.eq 'reach'
|
128
|
+
rescue Muack::Expected => e
|
129
|
+
e.expected .should.eq 'obj.say()'
|
130
|
+
e.expected_times.should.eq 3
|
131
|
+
e.actual_times .should.eq 2
|
132
|
+
e.message .should.eq "\nExpected: obj.say()\n " \
|
133
|
+
"called 3 times\n but was 2 times."
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
should 'show correct times for over satisfaction' do
|
138
|
+
stub(Obj).say
|
139
|
+
2.times{ Obj.say }
|
140
|
+
spy( Obj).say
|
141
|
+
begin
|
142
|
+
Muack.verify
|
143
|
+
'never'.should.eq 'reach'
|
144
|
+
rescue Muack::Expected => e
|
145
|
+
e.expected .should.eq 'obj.say()'
|
146
|
+
e.expected_times.should.eq 1
|
147
|
+
e.actual_times .should.eq 2
|
148
|
+
e.message .should.eq "\nExpected: obj.say()\n " \
|
149
|
+
"called 1 times\n but was 2 times."
|
150
|
+
end
|
151
|
+
end
|
61
152
|
end
|
62
153
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: muack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-06-
|
11
|
+
date: 2013-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
Muack -- Yet another mocking library.
|
@@ -35,12 +35,13 @@ files:
|
|
35
35
|
- lib/muack.rb
|
36
36
|
- lib/muack/any_instance_of.rb
|
37
37
|
- lib/muack/definition.rb
|
38
|
+
- lib/muack/error.rb
|
38
39
|
- lib/muack/failure.rb
|
39
40
|
- lib/muack/mock.rb
|
40
41
|
- lib/muack/modifier.rb
|
41
|
-
- lib/muack/proxy.rb
|
42
42
|
- lib/muack/satisfy.rb
|
43
43
|
- lib/muack/session.rb
|
44
|
+
- lib/muack/spy.rb
|
44
45
|
- lib/muack/stub.rb
|
45
46
|
- lib/muack/test.rb
|
46
47
|
- lib/muack/version.rb
|
data/lib/muack/proxy.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'muack/mock'
|
3
|
-
require 'muack/stub'
|
4
|
-
|
5
|
-
module Muack
|
6
|
-
module Proxy
|
7
|
-
def __mock_block_call defi, actual_args, actual_block
|
8
|
-
# handle block call in injected method, since we need to call origin
|
9
|
-
defi # but we still want to know which defi gets dispatched!
|
10
|
-
end
|
11
|
-
|
12
|
-
def __mock_inject_mock_method target, defi
|
13
|
-
mock = self # remember the context
|
14
|
-
target.__send__(:define_method, defi.msg){|*actual_args, &actual_block|
|
15
|
-
d = mock.__mock_dispatch(defi.msg, actual_args, actual_block)
|
16
|
-
|
17
|
-
ret = if d.original_method
|
18
|
-
__send__(d.original_method, *actual_args, &actual_block)
|
19
|
-
else
|
20
|
-
super(*actual_args, &actual_block)
|
21
|
-
end
|
22
|
-
|
23
|
-
if d.block
|
24
|
-
d.block.call(ret)
|
25
|
-
else
|
26
|
-
ret
|
27
|
-
end
|
28
|
-
}
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class MockProxy < Mock
|
33
|
-
include Proxy
|
34
|
-
end
|
35
|
-
|
36
|
-
class StubProxy < Stub
|
37
|
-
include Proxy
|
38
|
-
end
|
39
|
-
end
|