soveran-override 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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