soveran-override 0.0.5 → 0.0.6

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.
Files changed (4) hide show
  1. data/README.markdown +44 -2
  2. data/lib/override.rb +42 -1
  3. data/test/all_test.rb +117 -10
  4. metadata +1 -1
data/README.markdown CHANGED
@@ -17,17 +17,59 @@ Usage
17
17
 
18
18
  require 'override'
19
19
 
20
- @user = User.spawn
20
+ user = User.spawn
21
21
  override(@user, :name => "Foobar", :email => "foobar@example.org")
22
- override(User, :find => @user)
22
+ override(User, :find => user)
23
23
 
24
24
  Or alternatively:
25
25
 
26
26
  override(User, :find => override(User.spawn, :name => "Foobar, :email => "foobar@example.org"))
27
27
 
28
+ You can also send lambdas that will become the body of the redefined method:
29
+
30
+ user = User.spawn :name => "Foobar"
31
+ override(User, :find => lambda { |id| raise ArgumentError unless id == 1; user })
32
+
33
+ And then, in your tests:
34
+
35
+ assert_raise ArgumentError do
36
+ User.find(2)
37
+ end
38
+
39
+ assert_nothing_raised do
40
+ User.find(1)
41
+ end
42
+
43
+ assert_equal "Foobar", User.find(1).name
44
+
28
45
  In case you don't know what spawn means, check my other library for
29
46
  testing at http://github.com/soveran/spawner.
30
47
 
48
+ It is a common pattern to set expectations for method calls. You can do
49
+ it with the `expect` function:
50
+
51
+ user = User.spawn :name => "Foobar"
52
+ expect(User, :find, :return => user, :params => [:first, { :include => :friendships }])
53
+
54
+ And then:
55
+
56
+ assert_equal "Foobar", User.find(:first, :include => :friendships).name
57
+
58
+ This kind of tests encourage a very fine grained development
59
+ style. Testing side effects is possible with this and with many other
60
+ libraries, but it's something that should be avoided as much as
61
+ possible. Always keep in mind that a deterministic function is the
62
+ easiest to test, so the less coupling there is in the system, the more
63
+ reliable it becomes.
64
+
65
+ Note that this way of setting expectations doesn't count the number
66
+ of calls received by the redefined method. The RSpec equivalent of
67
+ `User.should_receive(:find).with(:first, :include => :friendships)`
68
+ triggers an exception if the method is not called. While it is a handy
69
+ feature, it encourages coupling and testing internals, so my advice
70
+ would be to use it scarcely and to try to refactor your code so it
71
+ doesn't follow this testing anti-pattern.
72
+
31
73
  Installation
32
74
  ------------
33
75
 
data/lib/override.rb CHANGED
@@ -25,13 +25,54 @@
25
25
  # drops the arguments passed to the redefined method. It's not necessary
26
26
  # in Ruby 1.8.
27
27
  #
28
+ # You can also send lambdas that will become the body of the redefined method:
29
+ #
30
+ # user = User.spawn :name => "Foobar"
31
+ # override(User, :find => lambda { |id| raise ArgumentError unless id == 1; user })
32
+ #
33
+ # And then, in your tests:
34
+ #
35
+ # assert_raise ArgumentError do
36
+ # User.find(2)
37
+ # end
38
+ #
39
+ # assert_nothing_raised do
40
+ # User.find(1)
41
+ # end
42
+ #
43
+ # assert_equal "Foobar", User.find(1).name
44
+ #
45
+ # It is a common pattern to set expectations for method calls. You can
46
+ # do it with the expect function:
47
+ #
48
+ # user = User.spawn :name => "Foobar"
49
+ # expect(User, :find, :return => user, :params => [:first, { :include => :friendships }])
50
+ #
51
+ # And then:
52
+ #
53
+ # assert_equal "Foobar", User.find(:first, :include => :friendships).name
54
+ # assert_raise ArgumentError do
55
+ # User.find(:all)
56
+ # end
57
+ #
28
58
  require "rubygems"
29
59
  require "metaid"
30
60
 
31
61
  def override object, methods
32
62
  methods.each do |method, result|
33
- object.meta_def(method) { |*_| result }
63
+ result.respond_to?(:to_proc) ?
64
+ object.meta_def(method, &result.to_proc) :
65
+ object.meta_def(method) { |*_| result }
34
66
  end
35
67
 
36
68
  object
37
69
  end
70
+
71
+ def expect object, method, options
72
+ expectation = lambda do |*params|
73
+ raise ArgumentError unless params == options[:params]
74
+ options[:return]
75
+ end
76
+
77
+ override(object, method => expectation)
78
+ end
data/test/all_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'test/unit'
2
2
  require 'rubygems'
3
- require 'shoulda'
3
+ require 'contest'
4
4
 
5
5
  require File.dirname(__FILE__) + "/../lib/override"
6
6
 
@@ -22,6 +22,14 @@ class Foo
22
22
  end
23
23
  end
24
24
 
25
+ class Callable
26
+ def to_proc
27
+ lambda do |name|
28
+ "Hello #{name}"
29
+ end
30
+ end
31
+ end
32
+
25
33
  class TestOverride < Test::Unit::TestCase
26
34
  context "dealing with arguments" do
27
35
  setup do
@@ -29,11 +37,11 @@ class TestOverride < Test::Unit::TestCase
29
37
  override(@foo, :bar => "Hello")
30
38
  end
31
39
 
32
- should "work without arguments" do
40
+ test "work without arguments" do
33
41
  assert_equal "Hello", @foo.bar
34
42
  end
35
43
 
36
- should "discard arguments" do
44
+ test "discard arguments" do
37
45
  assert_equal "Hello", @foo.bar(1)
38
46
  end
39
47
  end
@@ -44,17 +52,17 @@ class TestOverride < Test::Unit::TestCase
44
52
  @foo2 = Foo.new
45
53
  end
46
54
 
47
- should "work for string returns" do
55
+ test "work for string returns" do
48
56
  override(@foo, :bar => "Hello")
49
57
  assert_equal "Hello", @foo.bar
50
58
  end
51
59
 
52
- should "work for numeric returns" do
60
+ test "work for numeric returns" do
53
61
  override(@foo, :bar => 23)
54
62
  assert_equal 23, @foo.bar
55
63
  end
56
64
 
57
- should "work for object returns" do
65
+ test "work for object returns" do
58
66
  override(@foo, :bar => @foo2)
59
67
  assert_equal @foo2, @foo.bar
60
68
  end
@@ -65,19 +73,19 @@ class TestOverride < Test::Unit::TestCase
65
73
  @foo = Foo.new
66
74
  end
67
75
 
68
- should "work for methods that used to receive blocks" do
76
+ test "work for methods that used to receive blocks" do
69
77
  override(@foo, :baz => "Hey!")
70
78
  assert_equal "Hey!", @foo.baz { |x| x }
71
79
  end
72
80
 
73
- should "work for methods that used to receive arguments" do
81
+ test "work for methods that used to receive arguments" do
74
82
  override(@foo, :qux => "Yay!")
75
83
  assert_equal "Yay!", @foo.qux(1, 2, 3)
76
84
  end
77
85
  end
78
86
 
79
87
  context "rewriting multiple methods at once" do
80
- should "override all the passed methods" do
88
+ test "override all the passed methods" do
81
89
  override(@foo, :bar => 1, :baz => 2, :qux => 3)
82
90
  assert_equal 1, @foo.bar
83
91
  assert_equal 2, @foo.baz
@@ -86,8 +94,107 @@ class TestOverride < Test::Unit::TestCase
86
94
  end
87
95
 
88
96
  context "chaining successive calls" do
89
- should "return the object and allow chained calls" do
97
+ test "return the object and allow chained calls" do
90
98
  assert_equal 1, override(@foo, :bar => 1).bar
91
99
  end
92
100
  end
101
+
102
+ context "dealing with a proc as the result value" do
103
+ test "uses the proc as the body of the method" do
104
+ override(@foo, :bar => lambda { |name| "Hello #{name}" })
105
+ assert_equal "Hello World", @foo.bar("World")
106
+ end
107
+ end
108
+
109
+ context "using assert raise with lambdas" do
110
+ setup do
111
+ class User
112
+ def name
113
+ "Michel"
114
+ end
115
+ end
116
+
117
+ user = User.new
118
+ override(@foo, :bar => lambda { |id| raise ArgumentError unless id == 1; user })
119
+ end
120
+
121
+ test "lambdas should be able to raise exceptions" do
122
+ assert_raise ArgumentError do
123
+ @foo.bar(2)
124
+ end
125
+
126
+ assert_nothing_raised do
127
+ @foo.bar(1)
128
+ end
129
+
130
+ assert_equal "Michel", @foo.bar(1).name
131
+ end
132
+ end
133
+
134
+ context "documenting a gotcha with lambdas" do
135
+ setup do
136
+ name = "Michel"
137
+ @name = "Michel"
138
+ override(@foo, :bar => lambda { name })
139
+ override(@foo, :baz => lambda { @name })
140
+ end
141
+
142
+ test "succeeds when the lambda returns a local variable" do
143
+ assert_equal "Michel", @foo.bar
144
+ end
145
+
146
+ test "fails when the lambda is supposed to return an instance variable" do
147
+ assert_equal nil, @foo.baz
148
+ end
149
+ end
150
+
151
+ context "using objects that respond to to_proc" do
152
+ setup do
153
+ override(@foo, :bar => Callable.new)
154
+ end
155
+
156
+ test "coerces the value into a proc" do
157
+ assert_equal "Hello World", @foo.bar("World")
158
+ end
159
+ end
160
+
161
+ context "supporting procs as return values" do
162
+ setup do
163
+ override(@foo, :bar => lambda { lambda { "Hey!" } })
164
+ end
165
+
166
+ test "returns a lambda if it's wraped inside a proc" do
167
+ assert_equal "Hey!", @foo.bar.call
168
+ end
169
+ end
170
+
171
+ context "setting expectations" do
172
+ setup do
173
+ expect(@foo, :bar, :return => true, :params => ["Michel", 32])
174
+ end
175
+
176
+ test "raises an error if expectations are not met" do
177
+ assert_raise ArgumentError do
178
+ @foo.bar "Michel", 31
179
+ end
180
+ end
181
+
182
+ test "succeeds if expectations are met" do
183
+ assert_nothing_raised do
184
+ @foo.bar "Michel", 32
185
+ end
186
+ end
187
+ end
188
+
189
+ context "setting expectations with hashes in the param list" do
190
+ setup do
191
+ expect(@foo, :bar, :return => true, :params => ["Michel", { :include => :friendships, :select => "name" }])
192
+ end
193
+
194
+ test "succeeds if expectations are met" do
195
+ assert_nothing_raised do
196
+ @foo.bar "Michel", { :select => "name", :include => :friendships, :select => "name" }
197
+ end
198
+ end
199
+ end
93
200
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soveran-override
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens