mocoso 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c12b98f62eb01e570daf1a9101b16a168837ec7d
4
- data.tar.gz: cafcefb94d91446ff97bfb0e8ab72883be345101
3
+ metadata.gz: e5c21876105f80fb7e2c5f0f72b09406e83be714
4
+ data.tar.gz: af2c896fb182aa84454381aaa4060b3a04245078
5
5
  SHA512:
6
- metadata.gz: af1706795d43d65d19045663aee87eaf42448ef47c6a1147193282bf522000be8dfccb1800bd852c0bb5e09451dbab42d968ca943ba749c70354ca88a19a96f2
7
- data.tar.gz: 1a2aeaea3ae9b6f2b86a7c922c353c9c4173ffb00638c506921f7715ceba1315b5fac551241097175a15a9738a99a8b851dc04748e5f30cdf0854b451c32a686
6
+ metadata.gz: a5e18f8f38ba523988872a90be55bd2a3d0685258741fb13e238657c612c48c7fedbb1a2e9fa032f100b1ecb1d0385c817d62cfa7ad4b5b3b83c0ebf8960a402
7
+ data.tar.gz: 5f717db7f95cf129560e2e2c2f40b710d88860593e240d9d9afba63ee1fe99b5ac90ee8138f2edf3907933b2b7a5352c1332be6875527537c48227b9c908132f
data/README.md CHANGED
@@ -12,7 +12,7 @@ Motivation
12
12
  Yes, there are a lot of good libraries out there, but I wanted one that
13
13
  meets the following criteria:
14
14
 
15
- * Provides features to restore stubbed methods to their original implementations.
15
+ * Always restore stubbed methods to their original implementations.
16
16
  * Doesn't allow to stub or mock undefined methods.
17
17
  * Doesn't monkey-patch any class or object.
18
18
  * Test-framework agnostic (Doesn't need integration code).
@@ -36,14 +36,18 @@ A quick example (uses [Cutest][cutest]):
36
36
 
37
37
  test 'mocking a class method' do
38
38
  user = User.new
39
- expect User, :find, with: [1], return: user
40
- assert_equal user, User.find(1)
39
+
40
+ expect User, :find, with: [1], return: user do
41
+ assert_equal user, User.find(1)
42
+ end
41
43
  end
42
44
 
43
45
  test 'stubbing an instance method' do
44
46
  user = User.new
45
- stub user, valid?: true
46
- assert user.valid?
47
+
48
+ stub user, valid?: true do
49
+ assert user.valid?
50
+ end
47
51
  end
48
52
 
49
53
  Check [Official Documentation][docs] for more details.
data/lib/mocoso.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # Yet Another Simple Stub & Mock library, that also:
2
2
  #
3
- # - Provides features to restore stubbed methods to their original implementations.
3
+ # - Always restore stubbed methods to their original implementations.
4
4
  # - Doesn't allow to stub or mock undefined methods.
5
5
  # - Doesn't monkey-patch any class or object.
6
6
  # - Test-framework agnostic (Doesn't need integration code).
@@ -22,14 +22,18 @@
22
22
  #
23
23
  # test 'mocking a class method' do
24
24
  # user = User.new
25
- # expect User, :find, with: [1], return: user
26
- # assert_equal user, User.find(1)
25
+ #
26
+ # expect User, :find, with: [1], return: user do
27
+ # assert_equal user, User.find(1)
28
+ # end
27
29
  # end
28
30
  #
29
31
  # test 'stubbing an instance method' do
30
32
  # user = User.new
31
- # stub user, valid?: true
32
- # assert user.valid?
33
+ #
34
+ # stub user, valid?: true do
35
+ # assert user.valid?
36
+ # end
33
37
  # end
34
38
  #
35
39
  # Note: this example uses the test framework Cutest[1]:
@@ -44,33 +48,35 @@
44
48
  module Mocoso
45
49
  # Raised by #expect when a expectation is not fulfilled.
46
50
  #
47
- # Mocoso.expect object, :method, with: 'argument', returns: nil
48
- #
49
- # object.method 'unexpected argument'
50
- # # => Mocoso::ExpectationError: Expected ["argument"], got ["unexpected argument"]
51
+ # Mocoso.expect object, :method, with: 'argument', returns: nil do
52
+ # object.method 'unexpected argument'
53
+ # # => Mocoso::ExpectationError: Expected ["argument"], got ["unexpected argument"]
54
+ # end
51
55
  #
52
56
  ExpectationError = Class.new StandardError
53
57
 
54
- # Rewrites each method from `methods` and defined in +object+. `methods` is a
58
+ # Rewrites each method from +methods+ and defined in +object+. +methods+ is a
55
59
  # Hash that represents stubbed method name symbols as keys and corresponding
56
- # return values as values.
60
+ # return values as values. The methods are restored after the given +block+
61
+ # is executed.
57
62
  #
58
63
  # signup = SignupForm.new params[:user]
59
64
  #
60
65
  # signup.valid? # => false
61
- # signup.save # => false
62
- #
63
- # Mocoso.stub signup, valid?: true, signup: true
64
66
  #
65
- # signup.valid? # => true
66
- # signup.save # => true
67
+ # Mocoso.stub signup, :valid?, true do
68
+ # signup.valid? # => true
69
+ # end
67
70
  #
68
71
  # You can pass a callable object (responds to +call+) as a value:
69
72
  #
70
- # Mocoso.stub subject, foo: -> { "foo" }, bar: ->(value) { value }
73
+ # Mocoso.stub subject, foo: -> { "foo" } do
74
+ # subject.foo # => "foo"
75
+ # end
71
76
  #
72
- # subject.foo # => "foo"
73
- # subject.bar('foo') # => "foo"
77
+ # Mocoso.stub subject, :bar, ->(value) { value } do
78
+ # subject.bar('foo') # => "foo"
79
+ # end
74
80
  #
75
81
  # If you try to stub a method that is not defined by the +object+,
76
82
  # it raises an error.
@@ -78,79 +84,32 @@ module Mocoso
78
84
  # Mocoso.stub Object.new, undefined: nil
79
85
  # # => NameError: undefined method `undefined' for class `Object'
80
86
  #
81
- # Note that it will rewrite the method(s) in +object+. If you want to stub a
82
- # method without side effects, you should pass a block.
83
- #
84
- # User.all.length
85
- # # => 5
86
- #
87
- # Mocoso.stub User, all: [] do
88
- # User.all.length
89
- # # => 0
90
- # end
91
- #
92
- # User.all.length
93
- # # => 5
94
- #
95
- def stub object, methods
87
+ def stub object, method, result, &block
96
88
  metaclass = object.singleton_class
89
+ stubbed_method = "__mocoso_#{method}"
97
90
 
98
- methods.each do |method, result|
99
- metaclass.send :alias_method, stub_method_name(method), method
91
+ metaclass.send :alias_method, stubbed_method, method
100
92
 
101
- if result.respond_to?(:call)
102
- metaclass.send(:define_method, method) { |*args| result.call(*args) }
103
- else
104
- metaclass.send(:define_method, method) { result }
105
- end
106
- end
107
-
108
- if block_given?
109
- begin
110
- yield
111
- ensure
112
- unstub object, methods.keys
113
- end
93
+ if result.respond_to?(:call)
94
+ metaclass.send(:define_method, method) { |*args| result.(*args) }
95
+ else
96
+ metaclass.send(:define_method, method) { result }
114
97
  end
115
- end
116
-
117
- # Removes the specified stubbed +methods+ (added by calls to #stub or #expect) and
118
- # restores the original behaviour of the methods before they were stubbed.
119
- #
120
- # object.foo # => "foo"
121
- #
122
- # Mocoso.stub object, foo: 'new foo'
123
- # object.foo # => "new foo"
124
- #
125
- # Mocoso.unstub object, [:foo]
126
- # object.foo #=> "foo"
127
- #
128
- # I personally use a block on #stub or #expect to avoid side effects, because if
129
- # you #unstub a method which still has unsatisfied expectations, you may be
130
- # removing the only way those expectations can be satisfied. Use it on your
131
- # own responsibility.
132
- #
133
- # This method was born as a helper for #stub.
134
- #
135
- def unstub object, methods
136
- metaclass = object.singleton_class
137
98
 
138
- methods.each do |method|
99
+ begin
100
+ yield
101
+ ensure
139
102
  metaclass.send :undef_method, method
140
- metaclass.send :alias_method, method, stub_method_name(method)
141
- metaclass.send :undef_method, stub_method_name(method)
103
+ metaclass.send :alias_method, method, stubbed_method
104
+ metaclass.send :undef_method, stubbed_method
142
105
  end
143
106
  end
144
107
 
145
- def stub_method_name name
146
- "__mocoso_#{name}"
147
- end
148
- private :stub_method_name
149
-
150
108
  # Expect that method +method+ is called with the arguments specified in the
151
109
  # +:with+ option (defaults to +[]+ if it's not given) and returns the value
152
- # specified in the +:return+ option. If expectations are not met, it raises
153
- # Mocoso::ExpectationError error.
110
+ # specified in the +:returns+ option. If expectations are not met, it raises
111
+ # Mocoso::ExpectationError error. It uses #stub internally, so it will restore
112
+ # the methods to their original implementation after the +block+ is executed.
154
113
  #
155
114
  # class User < Model
156
115
  # end
@@ -158,40 +117,19 @@ module Mocoso
158
117
  # user = User[1]
159
118
  #
160
119
  # Mocoso.expect user, :update, with: [{ name: 'new name' }], returns: true
120
+ # subject.update unexpected: nil
121
+ # # => Mocoso::ExpectationError: Expected [{:name=>"new name"}], got [{:unexpected=>nil}]
161
122
  #
162
- # subject.update unexpected: nil
163
- # # => Mocoso::ExpectationError: Expected [{:name=>"new name"}], got [{:unexpected=>nil}]
164
- #
165
- # user.update name: 'new name'
166
- # # => true
167
- #
168
- # Note that it will rewrite the method in +object+. If you want to set an
169
- # expectation without side effects, you should pass a block.
170
- #
171
- # User.exists? 1
172
- # # => false
173
- #
174
- # Mocoso.expect User, :exists?, with: [1], returns: true do
175
- # User.exists? 1
123
+ # user.update name: 'new name'
176
124
  # # => true
177
125
  # end
178
126
  #
179
- # User.exists? 1
180
- # # => false
181
- #
182
- def expect object, method, options
127
+ def expect object, method, with: [], returns:, &block
183
128
  expectation = -> *params {
184
- with = options.fetch(:with) { [] }
185
-
186
129
  raise ExpectationError, "Expected #{with}, got #{params}" if params != with
187
-
188
- options[:return]
130
+ returns
189
131
  }
190
132
 
191
- if block_given?
192
- stub object, method => expectation, &proc
193
- else
194
- stub object, method => expectation
195
- end
133
+ stub object, method, expectation, &block
196
134
  end
197
135
  end
data/mocoso.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'mocoso'
5
- s.version = '0.0.2'
5
+ s.version = '0.1.0'
6
6
  s.summary = 'A simple stub & mock library'
7
7
  s.description = s.summary
8
8
  s.authors = ['Francesco Rodríguez']
@@ -17,104 +17,66 @@ setup do
17
17
  Subject.new
18
18
  end
19
19
 
20
- test 'raises error if object not respond to the given method' do |subject|
21
- assert_raise { stub(subject, nan: nil, undefined: nil) }
20
+ test 'raises error if block is not given' do |subject|
21
+ assert_raise { stub(subject, foo: 'foo') }
22
22
  end
23
23
 
24
- test 'stubs methods and return new values' do |subject|
25
- before_foo = subject.foo
26
- before_bar = subject.bar
27
-
28
- stub subject, foo: 'new foo', bar: 'new bar'
29
-
30
- assert subject.foo != before_foo
31
- assert subject.bar != before_bar
24
+ test 'raises error if object not respond to the given method' do |subject|
25
+ assert_raise(NameError) { stub(subject, :nan, nil) }
32
26
  end
33
27
 
34
- test 'stubs method with a callable object' do |subject|
28
+ test 'stubbed method return new value' do |subject|
35
29
  before = subject.foo
36
30
 
37
- stub subject, foo: -> { 'new foo' }
31
+ stub subject, :foo, 'new foo' do
32
+ assert_equal 'new foo', subject.foo
33
+ end
38
34
 
39
- assert subject.foo != before
40
- assert_equal 'new foo', subject.foo
35
+ assert_equal before, subject.foo
41
36
  end
42
37
 
43
- test 'stubs method with a callable object with arguments' do |subject|
38
+ test 'stubs method with a callable object' do |subject|
44
39
  before = subject.foo
45
40
 
46
- stub subject, foo: ->(a) { "new #{a}" }
41
+ stub subject, :foo, -> { 'new foo' } do
42
+ assert_equal 'new foo', subject.foo
43
+ end
47
44
 
48
- assert subject.foo('foo') != before
49
- assert_equal 'new foo', subject.foo('foo')
45
+ assert_equal before, subject.foo
50
46
  end
51
47
 
52
- test 'stubs method without side effects if a block is given' do
53
- before = Subject.foo
48
+ test 'stubs method with a callable object that requires arguments' do |subject|
49
+ before = subject.foo
54
50
 
55
- stub Subject, foo: 'new foo' do
56
- assert before != Subject.foo
51
+ stub subject, :foo, ->(a) { "new #{a}" } do
52
+ assert_equal 'new foo', subject.foo('foo')
57
53
  end
58
54
 
59
- assert_equal before, Subject.foo
55
+ assert_equal before, subject.foo
60
56
  end
61
57
 
62
58
  test 'succeeds if expectations are met' do |subject|
63
- expect subject, :baz, with: ['value'], return: 'result'
59
+ expect subject, :baz, with: ['value'], returns: 'result' do
60
+ assert_equal 'result', subject.baz('value')
61
+ end
64
62
 
65
- assert_equal 'result', subject.baz('value')
63
+ assert_equal 'baz', subject.baz('baz')
66
64
  end
67
65
 
68
66
  test 'raises an error if expectation are not met' do |subject|
69
- expect subject, :baz, with: ['value'], return: 'result'
70
-
71
- assert_raise(Mocoso::ExpectationError) { subject.baz('another') }
72
- end
73
-
74
- test 'expectation without side effects if a block is given' do |subject|
75
- expect subject, :baz, with: ['value'], return: 'mocked' do
76
- assert_equal 'mocked', subject.baz('value')
67
+ expect subject, :baz, with: ['value'], returns: 'result' do
68
+ assert_raise(Mocoso::ExpectationError) { subject.baz('another') }
77
69
  end
78
-
79
- assert_equal 'original', subject.baz('original')
80
70
  end
81
71
 
82
- test 'expectation without arguments' do |subject|
83
- expect subject, :foo, return: 'new foo'
84
-
85
- assert_equal 'new foo', subject.foo
72
+ test 'expectation without with option defaults to empty array' do |subject|
73
+ expect subject, :foo, returns: 'new foo' do
74
+ assert_equal 'new foo', subject.foo
75
+ end
86
76
  end
87
77
 
88
78
  test 'expectation with multiple arguments' do |subject|
89
- expect subject, :foo, with: ['new foo', { optional: true }], return: 'new foo'
90
-
91
- assert_equal 'new foo', subject.foo('new foo', optional: true)
92
- end
93
-
94
- test 'unstub removes specified stubbed methods' do |subject|
95
- before_foo = subject.foo
96
- before_bar = subject.bar
97
-
98
- stub subject, foo: 'new foo', bar: 'new bar', baz: 'new baz'
99
-
100
- assert before_foo != subject.foo
101
- assert before_bar != subject.bar
102
-
103
- unstub subject, [:foo, :bar]
104
-
105
- assert_equal before_foo, subject.foo
106
- assert_equal before_bar, subject.bar
107
- assert_equal 'new baz', subject.baz
108
- end
109
-
110
- test 'unstub removes specified expectations' do
111
- before = Subject.foo
112
-
113
- expect Subject, :foo, return: 'new foo'
114
-
115
- assert_equal 'new foo', Subject.foo
116
-
117
- unstub Subject, [:foo]
118
-
119
- assert_equal before, Subject.foo
79
+ expect subject, :foo, with: ['new foo', { optional: true }], returns: 'new foo' do
80
+ assert_equal 'new foo', subject.foo('new foo', optional: true)
81
+ end
120
82
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mocoso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Rodríguez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-03 00:00:00.000000000 Z
11
+ date: 2013-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cutest