lookout 3.0.0 → 3.0.1
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 +4 -4
- data/README +10 -7
- data/Rakefile +1 -5
- data/lib/lookout-3.0/version.rb +16 -4
- metadata +248 -243
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bb581b92138321c4bd16f652fc409144819e8e8
|
|
4
|
+
data.tar.gz: 98671835586ef400221e6dd5027930bdfab4ab11
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f2cacea2da550247f2dcfb709c0b830054c54fca2f229b8095a49ede2454337e4fc39f24e8e96140158d66afcb5bd931f53b0601dc9d32bdb5ff762e52a124fb
|
|
7
|
+
data.tar.gz: 3a2aa060d044b736609987c5604e5868d7afbdc6ea023023bbfa493e35571593a2f3cc01d8d1cd5749be2248698e0982cf4265c846287c3db69d41c634208f3d
|
data/README
CHANGED
|
@@ -666,8 +666,8 @@
|
|
|
666
666
|
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
|
|
667
667
|
² Read how 37signals had problems with slow Test::Unit tests at
|
|
668
668
|
http://37signals.com/svn/posts/2742-the-road-to-faster-tests/
|
|
669
|
-
³ Visit the Lookout-rack
|
|
670
|
-
http://
|
|
669
|
+
³ Visit the Lookout-rack home page at
|
|
670
|
+
http://disu.se/software/lookout-rack/
|
|
671
671
|
⁴ Visit the Rack Rubyforge project page at
|
|
672
672
|
http://rack.rubyforge.org/
|
|
673
673
|
|
|
@@ -812,7 +812,7 @@
|
|
|
812
812
|
donation to now@disu.se¹. Thanks! Your support won’t go unnoticed!
|
|
813
813
|
|
|
814
814
|
¹ Send a donation:
|
|
815
|
-
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now%40disu%2ese&item_name=
|
|
815
|
+
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now%40disu%2ese&item_name=Lookout
|
|
816
816
|
|
|
817
817
|
§ Reporting Bugs
|
|
818
818
|
|
|
@@ -830,9 +830,12 @@
|
|
|
830
830
|
|
|
831
831
|
¹ Add an issue to the Lookout issue tracker at https://github.com/now/lookout/issues
|
|
832
832
|
|
|
833
|
-
§
|
|
833
|
+
§ Licensing
|
|
834
834
|
|
|
835
|
-
|
|
836
|
-
|
|
835
|
+
Lookout is free software: you may redistribute it and/or modify it under
|
|
836
|
+
the terms of the {GNU Lesser General Public License, version 3}¹ or later²,
|
|
837
|
+
as published by the {Free Software Foundation}³.
|
|
837
838
|
|
|
838
|
-
¹
|
|
839
|
+
¹ See http://disu.se/licenses/lgpl-3.0/
|
|
840
|
+
² See http://gnu.org/licenses/
|
|
841
|
+
³ See http://fsf.org/
|
data/Rakefile
CHANGED
|
@@ -4,11 +4,7 @@ require 'inventory-rake-1.0'
|
|
|
4
4
|
|
|
5
5
|
load File.expand_path('../lib/lookout-3.0/version.rb', __FILE__)
|
|
6
6
|
|
|
7
|
-
Inventory::Rake::Tasks.define Lookout::Version
|
|
8
|
-
s.author = 'Nikolai Weibull'
|
|
9
|
-
s.email = 'now@bitwi.se'
|
|
10
|
-
s.homepage = 'https://github.com/now/lookout'
|
|
11
|
-
}
|
|
7
|
+
Inventory::Rake::Tasks.define Lookout::Version
|
|
12
8
|
|
|
13
9
|
Inventory::Rake::Tasks.unless_installing_dependencies do
|
|
14
10
|
require 'lookout-rake-3.0'
|
data/lib/lookout-3.0/version.rb
CHANGED
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
require 'inventory-1.0'
|
|
4
4
|
|
|
5
5
|
module Lookout
|
|
6
|
-
Version = Inventory.new(3, 0,
|
|
6
|
+
Version = Inventory.new(3, 0, 1){
|
|
7
|
+
authors{
|
|
8
|
+
author 'Nikolai Weibull', 'now@disu.se'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
homepage 'http://disu.se/software/lookout'
|
|
12
|
+
|
|
13
|
+
licenses{
|
|
14
|
+
license 'LGPLv3+',
|
|
15
|
+
'GNU Lesser General Public License, version 3 or later',
|
|
16
|
+
'http://www.gnu.org/licenses/'
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
def dependencies
|
|
8
20
|
super + Inventory::Dependencies.new{
|
|
9
|
-
development 'inventory-rake', 1,
|
|
10
|
-
development 'inventory-rake-tasks-yard', 1,
|
|
11
|
-
development 'lookout-rake', 3,
|
|
21
|
+
development 'inventory-rake', 1, 6, 0
|
|
22
|
+
development 'inventory-rake-tasks-yard', 1, 4, 0
|
|
23
|
+
development 'lookout-rake', 3, 1, 0
|
|
12
24
|
development 'yard', 0, 8, 0
|
|
13
25
|
development 'yard-heuristics', 1, 1, 0
|
|
14
26
|
development 'yard-value', 1, 2, 0
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lookout
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nikolai Weibull
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-04
|
|
11
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: inventory
|
|
@@ -16,56 +16,56 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ~>
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.5'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ~>
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
26
|
+
version: '1.5'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: inventory-rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ~>
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '1.
|
|
33
|
+
version: '1.6'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ~>
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '1.
|
|
40
|
+
version: '1.6'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: inventory-rake-tasks-yard
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ~>
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '1.
|
|
47
|
+
version: '1.4'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - ~>
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '1.
|
|
54
|
+
version: '1.4'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: lookout-rake
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - ~>
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '3.
|
|
61
|
+
version: '3.1'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - ~>
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '3.
|
|
68
|
+
version: '3.1'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: yard
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -125,7 +125,7 @@ dependencies:
|
|
|
125
125
|
description: |2
|
|
126
126
|
Lookout
|
|
127
127
|
|
|
128
|
-
Lookout is a unit testing framework for Ruby
|
|
128
|
+
Lookout is a unit testing framework for Ruby┬╣ that puts your results in
|
|
129
129
|
focus. Tests (expectations) are written as follows
|
|
130
130
|
|
|
131
131
|
expect 2 do
|
|
@@ -144,55 +144,55 @@ description: |2
|
|
|
144
144
|
[1, 2, 3].map{ |i| i * 2 }
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
Lookout is designed to encourage
|
|
147
|
+
Lookout is designed to encourage ΓÇô force, even ΓÇô unit testing best practices
|
|
148
148
|
such as
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
ΓÇó Setting up only one expectation per test
|
|
151
|
+
ΓÇó Not setting expectations on non-public APIs
|
|
152
|
+
ΓÇó Test isolation
|
|
153
153
|
|
|
154
154
|
This is done by
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
ΓÇó Only allowing one expectation to be set per test
|
|
157
|
+
ΓÇó Providing no (additional) way of accessing private state
|
|
158
|
+
ΓÇó Providing no setup and tear-down methods, nor a method of providing test
|
|
159
159
|
helpers
|
|
160
160
|
|
|
161
161
|
Other important points are
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
ΓÇó Putting the expected outcome of a test in focus with the steps of the
|
|
164
164
|
calculation of the actual result only as a secondary concern
|
|
165
|
-
|
|
165
|
+
ΓÇó A focus on code readability by providing no mechanism for describing an
|
|
166
166
|
expectation other than the code in the expectation itself
|
|
167
|
-
|
|
167
|
+
ΓÇó A unified syntax for setting up both state-based and behavior-based
|
|
168
168
|
expectations
|
|
169
169
|
|
|
170
|
-
The way Lookout works has been heavily influenced by expectations
|
|
171
|
-
{Jay Fields}
|
|
172
|
-
based at Subversion {revision 76}
|
|
173
|
-
the work past that revision are due to {Nikolai Weibull}
|
|
170
|
+
The way Lookout works has been heavily influenced by expectations┬▓, by
|
|
171
|
+
{Jay Fields}┬│. The code base was once also heavily based on expectations,
|
|
172
|
+
based at Subversion {revision 76}⁴. A lot has happened since then and all of
|
|
173
|
+
the work past that revision are due to {Nikolai Weibull}⁵.
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
┬╣ Ruby: http://ruby-lang.org/
|
|
176
|
+
┬▓ Expectations: http://expectations.rubyforge.org/
|
|
177
|
+
┬│ Jay FieldsΓÇÖs blog: http://blog.jayfields.com/
|
|
178
|
+
⁴ Lookout revision 76:
|
|
179
179
|
https://github.com/now/lookout/commit/537bedf3e5b3eb4b31c066b3266f42964ac35ebe
|
|
180
|
-
|
|
180
|
+
⁵ Nikolai Weibull’s home page: http://disu.se/
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
§ Installation
|
|
183
183
|
|
|
184
184
|
Install Lookout with
|
|
185
185
|
|
|
186
186
|
% gem install lookout
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
§ Usage
|
|
190
190
|
|
|
191
|
-
Lookout allows you to set expectations on an object
|
|
192
|
-
We
|
|
191
|
+
Lookout allows you to set expectations on an objectΓÇÖs state or behavior.
|
|
192
|
+
WeΓÇÖll begin by looking at state expectations and then take a look at
|
|
193
193
|
expectations on behavior.
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
§ Expectations on State: Literals
|
|
196
196
|
|
|
197
197
|
An expectation can be made on the result of a computation:
|
|
198
198
|
|
|
@@ -201,7 +201,7 @@ description: |2
|
|
|
201
201
|
end
|
|
202
202
|
|
|
203
203
|
Most objects, in fact, have their state expectations checked by invoking
|
|
204
|
-
|
|
204
|
+
‹#==› on the expected value with the result as its argument.
|
|
205
205
|
|
|
206
206
|
Checking that a result is within a given range is also simple:
|
|
207
207
|
|
|
@@ -209,29 +209,29 @@ description: |2
|
|
|
209
209
|
0.4 - 0.3
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
-
Here, the more general
|
|
212
|
+
Here, the more general ‹#===› is being used on the ‹Range›.
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
§ Regexps
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
‹Strings› of course match against ‹Strings›:
|
|
217
217
|
|
|
218
218
|
expect 'ab' do
|
|
219
219
|
'abc'[0..1]
|
|
220
220
|
end
|
|
221
221
|
|
|
222
|
-
but we can also match a
|
|
222
|
+
but we can also match a ‹String› against a ‹Regexp›:
|
|
223
223
|
|
|
224
224
|
expect %r{a substring} do
|
|
225
225
|
'a string with a substring'
|
|
226
226
|
end
|
|
227
227
|
|
|
228
|
-
(Note the use of
|
|
229
|
-
Ruby parses
|
|
228
|
+
(Note the use of ‹%r{…}› to avoid warnings that will be generated when
|
|
229
|
+
Ruby parses ‹expect /…/›.)
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
§ Modules
|
|
232
232
|
|
|
233
233
|
Checking that the result includes a certain module is done by expecting the
|
|
234
|
-
|
|
234
|
+
‹Module›.
|
|
235
235
|
|
|
236
236
|
expect Enumerable do
|
|
237
237
|
[]
|
|
@@ -244,13 +244,13 @@ description: |2
|
|
|
244
244
|
'a string'
|
|
245
245
|
end
|
|
246
246
|
|
|
247
|
-
This doesn
|
|
247
|
+
This doesn’t hinder us from expecting the actual ‹Module› itself:
|
|
248
248
|
|
|
249
249
|
expect Enumerable do
|
|
250
250
|
Enumerable
|
|
251
251
|
end
|
|
252
252
|
|
|
253
|
-
or the
|
|
253
|
+
or the ‹Class›:
|
|
254
254
|
|
|
255
255
|
expect String do
|
|
256
256
|
String
|
|
@@ -259,12 +259,12 @@ description: |2
|
|
|
259
259
|
for obvious reasons.
|
|
260
260
|
|
|
261
261
|
As you may have figured out yourself, this is accomplished by first
|
|
262
|
-
trying
|
|
263
|
-
expected
|
|
262
|
+
trying ‹#==› and, if it returns ‹false›, then trying ‹#===› on the
|
|
263
|
+
expected ‹Module›. This is also true of ‹Ranges› and ‹Regexps›.
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
§ Booleans
|
|
266
266
|
|
|
267
|
-
Truthfulness is expected with
|
|
267
|
+
Truthfulness is expected with ‹true› and ‹false›:
|
|
268
268
|
|
|
269
269
|
expect true do
|
|
270
270
|
1
|
|
@@ -274,7 +274,7 @@ description: |2
|
|
|
274
274
|
nil
|
|
275
275
|
end
|
|
276
276
|
|
|
277
|
-
Results equaling
|
|
277
|
+
Results equaling ‹true› or ‹false› are slightly different:
|
|
278
278
|
|
|
279
279
|
expect TrueClass do
|
|
280
280
|
true
|
|
@@ -286,9 +286,9 @@ description: |2
|
|
|
286
286
|
|
|
287
287
|
The rationale for this is that you should only care if the result of a
|
|
288
288
|
computation evaluates to a value that Ruby considers to be either true or
|
|
289
|
-
false, not the exact literals
|
|
289
|
+
false, not the exact literals ‹true› or ‹false›.
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
§ IO
|
|
292
292
|
|
|
293
293
|
Expecting output on an IO object is also common:
|
|
294
294
|
|
|
@@ -299,9 +299,9 @@ description: |2
|
|
|
299
299
|
This can be used to capture the output of a formatter that takes an
|
|
300
300
|
output object as a parameter.
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
§ Warnings
|
|
303
303
|
|
|
304
|
-
Expecting warnings from code isn
|
|
304
|
+
Expecting warnings from code isnΓÇÖt very common, but should be done:
|
|
305
305
|
|
|
306
306
|
expect warning('this is your final one!') do
|
|
307
307
|
warn 'this is your final one!'
|
|
@@ -311,9 +311,9 @@ description: |2
|
|
|
311
311
|
warn '%s:%d: warning: this is your final one!' % [__FILE__, __LINE__]
|
|
312
312
|
end
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
don
|
|
316
|
-
value of $VERBOSE, that can be done with
|
|
314
|
+
‹$VERBOSE› is set to ‹true› during the execution of the block, so you
|
|
315
|
+
donΓÇÖt need to do so yourself. If you have other code that depends on the
|
|
316
|
+
value of $VERBOSE, that can be done with ‹#with_verbose›
|
|
317
317
|
|
|
318
318
|
expect nil do
|
|
319
319
|
with_verbose nil do
|
|
@@ -321,10 +321,10 @@ description: |2
|
|
|
321
321
|
end
|
|
322
322
|
end
|
|
323
323
|
|
|
324
|
-
|
|
324
|
+
§ Errors
|
|
325
325
|
|
|
326
|
-
You should always be expecting errors from
|
|
327
|
-
different story
|
|
326
|
+
You should always be expecting errors from ΓÇô and in, but thatΓÇÖs a
|
|
327
|
+
different story ΓÇô your code:
|
|
328
328
|
|
|
329
329
|
expect ArgumentError do
|
|
330
330
|
Integer('1 + 1')
|
|
@@ -337,25 +337,25 @@ description: |2
|
|
|
337
337
|
raise StandardError.new('message')
|
|
338
338
|
end
|
|
339
339
|
|
|
340
|
-
As with
|
|
340
|
+
As with ‹Strings›, ‹Regexps› can be used to check the error description:
|
|
341
341
|
|
|
342
342
|
expect StandardError.new(/mess/) do
|
|
343
343
|
raise StandardError.new('message')
|
|
344
344
|
end
|
|
345
345
|
|
|
346
|
-
|
|
346
|
+
§ Queries Through Symbols
|
|
347
347
|
|
|
348
348
|
Symbols are generally matched against symbols, but as a special case,
|
|
349
|
-
symbols ending with
|
|
349
|
+
symbols ending with ‹?› are seen as expectations on the result of query
|
|
350
350
|
methods on the result of the block, given that the method is of zero
|
|
351
|
-
arity and that the result isn
|
|
352
|
-
ending with
|
|
351
|
+
arity and that the result isnΓÇÖt a Symbol itself. Simply expect a symbol
|
|
352
|
+
ending with ‹?›:
|
|
353
353
|
|
|
354
354
|
expect :empty? do
|
|
355
355
|
[]
|
|
356
356
|
end
|
|
357
357
|
|
|
358
|
-
To expect it
|
|
358
|
+
To expect it’s negation, expect the same symbol beginning with ‹not_›:
|
|
359
359
|
|
|
360
360
|
expect :not_nil? do
|
|
361
361
|
[1, 2, 3]
|
|
@@ -374,19 +374,19 @@ description: |2
|
|
|
374
374
|
end
|
|
375
375
|
|
|
376
376
|
but provides much clearer failure messages. It also makes the
|
|
377
|
-
expectation
|
|
377
|
+
expectationΓÇÖs intent a lot clearer.
|
|
378
378
|
|
|
379
|
-
|
|
379
|
+
§ Queries By Proxy
|
|
380
380
|
|
|
381
|
-
There
|
|
381
|
+
ThereΓÇÖs also a way to make the expectations of query methods explicit by
|
|
382
382
|
invoking methods on the result of the block. For example, to check that
|
|
383
|
-
the even elements of the Array
|
|
383
|
+
the even elements of the Array ‹[1, 2, 3]› include ‹1› you could write
|
|
384
384
|
|
|
385
385
|
expect result.to.include? 1 do
|
|
386
386
|
[1, 2, 3].reject{ |e| e.even? }
|
|
387
387
|
end
|
|
388
388
|
|
|
389
|
-
You could likewise check that the result doesn
|
|
389
|
+
You could likewise check that the result doesnΓÇÖt include 2:
|
|
390
390
|
|
|
391
391
|
expect result.not.to.include? 2 do
|
|
392
392
|
[1, 2, 3].reject{ |e| e.even? }
|
|
@@ -399,34 +399,34 @@ description: |2
|
|
|
399
399
|
end
|
|
400
400
|
|
|
401
401
|
but provides much clearer failure messages. Given that these two last
|
|
402
|
-
examples would fail, you
|
|
403
|
-
instead of the terser
|
|
402
|
+
examples would fail, youΓÇÖd get a message saying ΓÇ£[1, 2, 3]#include?(2)ΓÇ¥
|
|
403
|
+
instead of the terser ΓÇ£trueΓëáfalseΓÇ¥. It also clearly separates the actual
|
|
404
404
|
expectation from the set-up.
|
|
405
405
|
|
|
406
|
-
The keyword for this kind of expectations is
|
|
406
|
+
The keyword for this kind of expectations is ‹result›. This may be
|
|
407
407
|
followed by any of the methods
|
|
408
408
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
409
|
+
• ‹#not›
|
|
410
|
+
• ‹#to›
|
|
411
|
+
• ‹#be›
|
|
412
|
+
• ‹#have›
|
|
413
413
|
|
|
414
414
|
or any other method you will want to call on the result. The methods
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
‹#to›, ‹#be›, and ‹#have› do nothing except improve readability. The
|
|
416
|
+
‹#not› method inverts the expectation.
|
|
417
417
|
|
|
418
|
-
|
|
418
|
+
§ Literal Literals
|
|
419
419
|
|
|
420
420
|
If you need to literally check against any of the types of objects
|
|
421
421
|
otherwise treated specially, that is, any instances of
|
|
422
422
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
423
|
+
• ‹Module›
|
|
424
|
+
• ‹Range›
|
|
425
|
+
• ‹Regexp›
|
|
426
|
+
• ‹Exception›
|
|
427
|
+
• ‹Symbol›, given that it ends with ‹?›
|
|
428
428
|
|
|
429
|
-
you can do so by wrapping it in
|
|
429
|
+
you can do so by wrapping it in ‹literal(…)›:
|
|
430
430
|
|
|
431
431
|
expect literal(:empty?) do
|
|
432
432
|
:empty?
|
|
@@ -435,7 +435,7 @@ description: |2
|
|
|
435
435
|
You almost never need to do this, as, for all but symbols, instances will
|
|
436
436
|
match accordingly as well.
|
|
437
437
|
|
|
438
|
-
|
|
438
|
+
§ Expectations on Behavior
|
|
439
439
|
|
|
440
440
|
We expect our objects to be on their best behavior. Lookout allows you
|
|
441
441
|
to make sure that they are.
|
|
@@ -447,15 +447,15 @@ description: |2
|
|
|
447
447
|
o.to_str
|
|
448
448
|
end
|
|
449
449
|
|
|
450
|
-
Here,
|
|
450
|
+
Here, ‹#mock› creates a mock object, an object that doesn’t respond to
|
|
451
451
|
anything unless you tell it to. We tell it to expect to receive a call
|
|
452
|
-
to
|
|
452
|
+
to ‹#to_str› without arguments and have ‹#to_str› return ‹'123'› when
|
|
453
453
|
called. The mock object is then passed in to the block so that the
|
|
454
454
|
expectations placed upon it can be fulfilled.
|
|
455
455
|
|
|
456
456
|
Sometimes we only want to make sure that a method is called in the way
|
|
457
|
-
that we expect it to be, but we don
|
|
458
|
-
called on the object. A stub object, created with
|
|
457
|
+
that we expect it to be, but we donΓÇÖt care if any other methods are
|
|
458
|
+
called on the object. A stub object, created with ‹#stub›, expects any
|
|
459
459
|
method and returns a stub object that, again, expects any method, and
|
|
460
460
|
thus fits the bill.
|
|
461
461
|
|
|
@@ -463,30 +463,30 @@ description: |2
|
|
|
463
463
|
o.to_str if o.convertable?
|
|
464
464
|
end
|
|
465
465
|
|
|
466
|
-
You don
|
|
466
|
+
You donΓÇÖt have to use a mock object to verify that a method is called:
|
|
467
467
|
|
|
468
468
|
expect Object.to.receive.name do
|
|
469
469
|
Object.name
|
|
470
470
|
end
|
|
471
471
|
|
|
472
472
|
As you have figured out by now, the expected method call is set up by
|
|
473
|
-
calling
|
|
473
|
+
calling ‹#receive› after ‹#to›. ‹#Receive› is followed by a call to the
|
|
474
474
|
method to expect with any expected arguments. The body of the expected
|
|
475
475
|
method can be given as the block to the method. Finally, an expected
|
|
476
|
-
invocation count may follow the method. Let
|
|
476
|
+
invocation count may follow the method. LetΓÇÖs look at this formal
|
|
477
477
|
specification in more detail.
|
|
478
478
|
|
|
479
|
-
The expected method arguments may be given in a variety of ways. Let
|
|
479
|
+
The expected method arguments may be given in a variety of ways. LetΓÇÖs
|
|
480
480
|
introduce them by giving some examples:
|
|
481
481
|
|
|
482
482
|
expect mock.to.receive.a do |m|
|
|
483
483
|
m.a
|
|
484
484
|
end
|
|
485
485
|
|
|
486
|
-
Here, the method
|
|
486
|
+
Here, the method ‹#a› must be called with any number of arguments. It
|
|
487
487
|
may be called any number of times, but it must be called at least once.
|
|
488
488
|
|
|
489
|
-
If a method must receive exactly one argument, you can use
|
|
489
|
+
If a method must receive exactly one argument, you can use ‹Object›, as
|
|
490
490
|
the same matching rules apply for arguments as they do for state
|
|
491
491
|
expectations:
|
|
492
492
|
|
|
@@ -501,24 +501,24 @@ description: |2
|
|
|
501
501
|
end
|
|
502
502
|
|
|
503
503
|
Again, the same matching rules apply for arguments as they do for state
|
|
504
|
-
expectations, so the previous example expects a call to
|
|
505
|
-
or the Range 1..2 as an argument on
|
|
504
|
+
expectations, so the previous example expects a call to ‹#a› with 1, 2,
|
|
505
|
+
or the Range 1..2 as an argument on ‹m›.
|
|
506
506
|
|
|
507
507
|
If a method must be invoked without any arguments you can use
|
|
508
|
-
|
|
508
|
+
‹without_arguments›:
|
|
509
509
|
|
|
510
510
|
expect mock.to.receive.a(without_arguments) do |m|
|
|
511
511
|
m.a
|
|
512
512
|
end
|
|
513
513
|
|
|
514
|
-
You can of course use both
|
|
514
|
+
You can of course use both ‹Object› and actual arguments:
|
|
515
515
|
|
|
516
516
|
expect mock.to.receive.a(Object, 2, Object) do |m|
|
|
517
517
|
m.a nil, 2, '3'
|
|
518
518
|
end
|
|
519
519
|
|
|
520
520
|
The body of the expected method may be given as the block. Here, calling
|
|
521
|
-
|
|
521
|
+
‹#a› on ‹m› will give the result ‹1›:
|
|
522
522
|
|
|
523
523
|
expect mock.to.receive.a{ 1 } do |m|
|
|
524
524
|
raise 'not 1' unless m.a == 1
|
|
@@ -526,7 +526,7 @@ description: |2
|
|
|
526
526
|
|
|
527
527
|
If no body has been given, the result will be a stub object.
|
|
528
528
|
|
|
529
|
-
To take a block, grab a block parameter and
|
|
529
|
+
To take a block, grab a block parameter and ‹#call› it:
|
|
530
530
|
|
|
531
531
|
expect mock.to.receive.a{ |&b| b.call(1) } do |m|
|
|
532
532
|
j = 0
|
|
@@ -534,34 +534,34 @@ description: |2
|
|
|
534
534
|
raise 'not 1' unless j == 1
|
|
535
535
|
end
|
|
536
536
|
|
|
537
|
-
To simulate an
|
|
537
|
+
To simulate an ‹#each›-like method, ‹#call› the block several times.
|
|
538
538
|
|
|
539
539
|
Invocation count expectations can be set if the default expectation of
|
|
540
|
-
|
|
540
|
+
ΓÇ£at least onceΓÇ¥ isnΓÇÖt good enough. The following expectations are
|
|
541
541
|
possible
|
|
542
542
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
543
|
+
• ‹#at_most_once›
|
|
544
|
+
• ‹#once›
|
|
545
|
+
• ‹#at_least_once›
|
|
546
|
+
• ‹#twice›
|
|
547
547
|
|
|
548
|
-
And, for a given
|
|
548
|
+
And, for a given ‹N›,
|
|
549
549
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
550
|
+
• ‹#at_most(N)›
|
|
551
|
+
• ‹#exactly(N)›
|
|
552
|
+
• ‹#at_least(N)›
|
|
553
553
|
|
|
554
|
-
|
|
554
|
+
§ Utilities: Stubs
|
|
555
555
|
|
|
556
556
|
Method stubs are another useful thing to have in a unit testing
|
|
557
557
|
framework. Sometimes you need to override a method that does something a
|
|
558
|
-
test shouldn
|
|
559
|
-
|
|
560
|
-
have an
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
test we want to make sure that
|
|
564
|
-
accessing the database. We therefore stub out
|
|
558
|
+
test shouldnΓÇÖt do, like access and alter bank accounts. We can override
|
|
559
|
+
– stub out – a method by using the ‹#stub› method. Let’s assume that we
|
|
560
|
+
have an ‹Account› class that has two methods, ‹#slips› and ‹#total›.
|
|
561
|
+
‹#Slips› retrieves the bank slips that keep track of your deposits to the
|
|
562
|
+
‹Account› from a database. ‹#Total› sums the ‹#slips›. In the following
|
|
563
|
+
test we want to make sure that ‹#total› does what it should do without
|
|
564
|
+
accessing the database. We therefore stub out ‹#slips› and make it
|
|
565
565
|
return something that we can easily control.
|
|
566
566
|
|
|
567
567
|
expect 6 do |m|
|
|
@@ -576,7 +576,7 @@ description: |2
|
|
|
576
576
|
}.new, :slips => [1, 2, 3]){ |account| account.total }
|
|
577
577
|
end
|
|
578
578
|
|
|
579
|
-
To make it easy to create objects with a set of stubbed methods there
|
|
579
|
+
To make it easy to create objects with a set of stubbed methods thereΓÇÖs
|
|
580
580
|
also a convenience method:
|
|
581
581
|
|
|
582
582
|
expect 3 do
|
|
@@ -611,10 +611,10 @@ description: |2
|
|
|
611
611
|
|
|
612
612
|
The stub is active during the execution of the block.
|
|
613
613
|
|
|
614
|
-
|
|
614
|
+
§ Overriding Constants
|
|
615
615
|
|
|
616
616
|
Sometimes you need to override the value of a constant during the
|
|
617
|
-
execution of some code. Use
|
|
617
|
+
execution of some code. Use ‹#with_const› to do just that:
|
|
618
618
|
|
|
619
619
|
expect 'hello' do
|
|
620
620
|
with_const 'A::B::C', 'hello' do
|
|
@@ -622,19 +622,19 @@ description: |2
|
|
|
622
622
|
end
|
|
623
623
|
end
|
|
624
624
|
|
|
625
|
-
Here, the constant
|
|
626
|
-
the block. None of the constants
|
|
627
|
-
this to work. If a constant doesn
|
|
628
|
-
empty,
|
|
629
|
-
block returns and any constants that didn
|
|
625
|
+
Here, the constant ‹A::B::C› is set to ‹'hello'› during the execution of
|
|
626
|
+
the block. None of the constants ‹A›, ‹B›, and ‹C› need to exist for
|
|
627
|
+
this to work. If a constant doesnΓÇÖt exist itΓÇÖs created and set to a new,
|
|
628
|
+
empty, ‹Module›. The value of ‹A::B::C›, if any, is restored after the
|
|
629
|
+
block returns and any constants that didnΓÇÖt previously exist are removed.
|
|
630
630
|
|
|
631
|
-
|
|
631
|
+
§ Overriding Environment Variables
|
|
632
632
|
|
|
633
633
|
Another thing you often need to control in your tests is the value of
|
|
634
634
|
environment variables. Depending on such global values is, of course,
|
|
635
635
|
not a good practice, but is often unavoidable when working with external
|
|
636
|
-
libraries.
|
|
637
|
-
variables during the execution of a block by giving it a
|
|
636
|
+
libraries. ‹#With_env› allows you to override the value of environment
|
|
637
|
+
variables during the execution of a block by giving it a ‹Hash› of
|
|
638
638
|
key/value pairs where the key is the name of the environment variable and
|
|
639
639
|
the value is the value that it should have during the execution of that
|
|
640
640
|
block:
|
|
@@ -645,10 +645,10 @@ description: |2
|
|
|
645
645
|
end
|
|
646
646
|
end
|
|
647
647
|
|
|
648
|
-
Any overridden values are restored and any keys that weren
|
|
648
|
+
Any overridden values are restored and any keys that werenΓÇÖt previously a
|
|
649
649
|
part of the environment are removed when the block returns.
|
|
650
650
|
|
|
651
|
-
|
|
651
|
+
§ Overriding Globals
|
|
652
652
|
|
|
653
653
|
You may also want to override the value of a global temporarily:
|
|
654
654
|
|
|
@@ -669,9 +669,9 @@ description: |2
|
|
|
669
669
|
end
|
|
670
670
|
end
|
|
671
671
|
|
|
672
|
-
|
|
672
|
+
§ Integration
|
|
673
673
|
|
|
674
|
-
Lookout can be used from Rake
|
|
674
|
+
Lookout can be used from Rake┬╣. Simply install Lookout-Rake┬▓:
|
|
675
675
|
|
|
676
676
|
% gem install lookout-rake
|
|
677
677
|
|
|
@@ -684,17 +684,17 @@ description: |2
|
|
|
684
684
|
Make sure to read up on using Lookout-Rake for further benefits and
|
|
685
685
|
customization.
|
|
686
686
|
|
|
687
|
-
|
|
688
|
-
|
|
687
|
+
┬╣ Read more about Rake at http://rake.rubyforge.org/
|
|
688
|
+
┬▓ Get information on Lookout-Rake at http://disu.se/software/lookout-rake/
|
|
689
689
|
|
|
690
|
-
|
|
690
|
+
§ API
|
|
691
691
|
|
|
692
|
-
Lookout comes with an API
|
|
692
|
+
Lookout comes with an API┬╣ that letΓÇÖs you create things such as new
|
|
693
693
|
expected values, difference reports for your types, and so on.
|
|
694
694
|
|
|
695
|
-
|
|
695
|
+
┬╣ See http://disu.se/software/lookout/api/
|
|
696
696
|
|
|
697
|
-
|
|
697
|
+
§ Interface Design
|
|
698
698
|
|
|
699
699
|
The default output of Lookout can Spartanly be described as Spartan. If no
|
|
700
700
|
errors or failures occur, no output is generated. This is unconventional,
|
|
@@ -703,44 +703,44 @@ description: |2
|
|
|
703
703
|
colored text telling you that your tests passed. None of this output is
|
|
704
704
|
needed. Your tests should run fast enough to not require progress reports.
|
|
705
705
|
The lack of output provides you with the same amount of information as
|
|
706
|
-
reporting success. Test count summaries are only useful if you
|
|
707
|
-
that your tests aren
|
|
708
|
-
providing such output doesn
|
|
706
|
+
reporting success. Test count summaries are only useful if youΓÇÖre worried
|
|
707
|
+
that your tests arenΓÇÖt being run, but if you worry about that, then
|
|
708
|
+
providing such output doesnΓÇÖt really help. Testing your tests requires
|
|
709
709
|
something beyond reporting some arbitrary count that you would have to
|
|
710
710
|
verify by hand anyway.
|
|
711
711
|
|
|
712
712
|
When errors or failures do occur, however, the relevant information is
|
|
713
|
-
output in a format that can easily be parsed by an
|
|
714
|
-
or with {Compilation Mode}
|
|
713
|
+
output in a format that can easily be parsed by an ‹'errorformat'› for Vim
|
|
714
|
+
or with {Compilation Mode}┬╣ for Emacs┬▓. Diffs are generated for Strings,
|
|
715
715
|
Arrays, Hashes, and I/O.
|
|
716
716
|
|
|
717
|
-
|
|
718
|
-
|
|
717
|
+
┬╣ Read up on Compilation mode for Emacs at http://www.emacswiki.org/emacs/CompilationMode
|
|
718
|
+
┬▓ Visit The GNU FoundationΓÇÖs EmacsΓÇÖ software page at http://www.gnu.org/software/emacs/
|
|
719
719
|
|
|
720
|
-
|
|
720
|
+
§ External Design
|
|
721
721
|
|
|
722
|
-
Let
|
|
722
|
+
LetΓÇÖs now look at some of the points made in the introduction in greater
|
|
723
723
|
detail.
|
|
724
724
|
|
|
725
|
-
Lookout only allows you to set one expectation per test. If you
|
|
725
|
+
Lookout only allows you to set one expectation per test. If youΓÇÖre testing
|
|
726
726
|
behavior with a reception expectation, then only one method-invocation
|
|
727
|
-
expectation can be set. If you
|
|
727
|
+
expectation can be set. If youΓÇÖre testing state, then only one result can
|
|
728
728
|
be verified. It may seem like this would cause unnecessary duplication
|
|
729
729
|
between tests. While this is certainly a possibility, when you actually
|
|
730
730
|
begin to try to avoid such duplication you find that you often do so by
|
|
731
731
|
improving your interfaces. This kind of restriction tends to encourage the
|
|
732
732
|
use of value objects, which are easy to test, and more focused objects,
|
|
733
733
|
which require simpler tests, as they have less behavior to test, per
|
|
734
|
-
method. By keeping your interfaces focused you
|
|
734
|
+
method. By keeping your interfaces focused youΓÇÖre also keeping your tests
|
|
735
735
|
focused.
|
|
736
736
|
|
|
737
|
-
Keeping your tests focused improves, in itself, test isolation, but let
|
|
737
|
+
Keeping your tests focused improves, in itself, test isolation, but letΓÇÖs
|
|
738
738
|
look at something that hinders it: setup and tear-down methods. Most unit
|
|
739
739
|
testing frameworks encourage test fragmentation by providing setup and
|
|
740
740
|
tear-down methods.
|
|
741
741
|
|
|
742
742
|
Setup methods create objects and, perhaps, just their behavior for a set of
|
|
743
|
-
tests. This means that you have to look in two places to figure out what
|
|
743
|
+
tests. This means that you have to look in two places to figure out whatΓÇÖs
|
|
744
744
|
being done in a test. This may work fine for few methods with simple
|
|
745
745
|
set-ups, but makes things complicated when the number of tests increases
|
|
746
746
|
and the set-up is complex. Often, each test further adjusts the previously
|
|
@@ -753,32 +753,32 @@ description: |2
|
|
|
753
753
|
The duplication that setup methods and tear-down methods hope to remove is
|
|
754
754
|
better avoided by improving your interfaces. This can be done by providing
|
|
755
755
|
better set-up methods for your objects and using idioms such as {Resource
|
|
756
|
-
Acquisition Is Initialization}
|
|
756
|
+
Acquisition Is Initialization}┬╣ for guaranteed clean-up, test or no test.
|
|
757
757
|
|
|
758
758
|
By not using setup and tear-down methods we keep everything pertinent to a
|
|
759
|
-
test in the test itself, thus improving test isolation. (You also won
|
|
760
|
-
{slow down your tests}
|
|
759
|
+
test in the test itself, thus improving test isolation. (You also wonΓÇÖt
|
|
760
|
+
{slow down your tests}┬▓ by keeping unnecessary state.)
|
|
761
761
|
|
|
762
762
|
Most unit test frameworks also allow you to create arbitrary test helper
|
|
763
|
-
methods. Lookout doesn
|
|
763
|
+
methods. Lookout doesnΓÇÖt. The same rationale as that that has been
|
|
764
764
|
crystallized in the preceding paragraphs applies. If you need helpers
|
|
765
|
-
you
|
|
765
|
+
youΓÇÖre interface isnΓÇÖt good enough. It really is as simple as that.
|
|
766
766
|
|
|
767
|
-
To clarify: there
|
|
767
|
+
To clarify: thereΓÇÖs nothing inherently wrong with test helper methods, but
|
|
768
768
|
they should be general enough that they reside in their own library. The
|
|
769
769
|
support for mocks in Lookout is provided through a set of test helper
|
|
770
770
|
methods that make it easier to create mocks than it would have been without
|
|
771
|
-
them. Lookout-rack
|
|
771
|
+
them. Lookout-rack┬│ is another example of a library providing test helper
|
|
772
772
|
methods (well, one method, actually) that are very useful in testing web
|
|
773
|
-
applications that use Rack
|
|
773
|
+
applications that use Rack⁴.
|
|
774
774
|
|
|
775
775
|
A final point at which some unit test frameworks try to fragment tests
|
|
776
776
|
further is documentation. These frameworks provide ways of describing the
|
|
777
|
-
whats and hows of what
|
|
777
|
+
whats and hows of whatΓÇÖs being tested, the rationale being that this will
|
|
778
778
|
provide documentation of both the test and the code being tested.
|
|
779
779
|
Describing how a stack data structure is meant to work is a common example.
|
|
780
780
|
A stack is, however, a rather simple data structure, so such a description
|
|
781
|
-
provides little, if any, additional information that can
|
|
781
|
+
provides little, if any, additional information that canΓÇÖt be extracted
|
|
782
782
|
from the implementation and its tests themselves. The implementation and
|
|
783
783
|
its tests is, in fact, its own best documentation. Taking the points made
|
|
784
784
|
in the previous paragraphs into account, we should already have simple,
|
|
@@ -787,144 +787,144 @@ description: |2
|
|
|
787
787
|
system-design design documentation is better suited in separate
|
|
788
788
|
documentation focused at describing exactly those issues.
|
|
789
789
|
|
|
790
|
-
|
|
790
|
+
┬╣ Read the Wikipedia entry for Resource Acquisition Is Initialization at
|
|
791
791
|
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
|
|
792
|
-
|
|
792
|
+
┬▓ Read how 37signals had problems with slow Test::Unit tests at
|
|
793
793
|
http://37signals.com/svn/posts/2742-the-road-to-faster-tests/
|
|
794
|
-
|
|
795
|
-
http://
|
|
796
|
-
|
|
794
|
+
┬│ Visit the Lookout-rack home page at
|
|
795
|
+
http://disu.se/software/lookout-rack/
|
|
796
|
+
⁴ Visit the Rack Rubyforge project page at
|
|
797
797
|
http://rack.rubyforge.org/
|
|
798
798
|
|
|
799
|
-
|
|
799
|
+
§ Internal Design
|
|
800
800
|
|
|
801
801
|
The internal design of Lookout has had a couple of goals.
|
|
802
802
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
803
|
+
ΓÇó As few external dependencies as possible
|
|
804
|
+
ΓÇó As few internal dependencies as possible
|
|
805
|
+
ΓÇó Internal extensibility provides external extensibility
|
|
806
|
+
ΓÇó As fast load times as possible
|
|
807
|
+
ΓÇó As high a ratio of value objects to mutable objects as possible
|
|
808
|
+
ΓÇó Each object must have a simple, obvious name
|
|
809
|
+
ΓÇó Use mix-ins, not inheritance for shared behavior
|
|
810
|
+
ΓÇó As few responsibilities per object as possible
|
|
811
|
+
ΓÇó Optimizing for speed can only be done when you have all the facts
|
|
812
812
|
|
|
813
|
-
|
|
813
|
+
§ External Dependencies
|
|
814
814
|
|
|
815
815
|
Lookout used to depend on Mocha for mocks and stubs. While benchmarking I
|
|
816
816
|
noticed that a method in Mocha was taking up more than 300 percent of the
|
|
817
|
-
runtime. It turned out that Mocha
|
|
817
|
+
runtime. It turned out that MochaΓÇÖs method for cleaning up back-traces
|
|
818
818
|
generated when a mock failed was doing something incredibly stupid:
|
|
819
819
|
|
|
820
820
|
backtrace.reject{ |l| Regexp.new(@lib).match(File.expand_path(l)) }
|
|
821
821
|
|
|
822
|
-
Here
|
|
822
|
+
Here ‹@lib› is a ‹String› containing the path to the lib sub-directory in
|
|
823
823
|
the Mocha installation directory. I reported it, provided a patch five
|
|
824
|
-
days later, then waited. Nothing happened. {254 days later}
|
|
825
|
-
to {Wolfram Alpha}
|
|
826
|
-
as I received no notification
|
|
824
|
+
days later, then waited. Nothing happened. {254 days later}┬╣, according
|
|
825
|
+
to {Wolfram Alpha}┬▓, half of my patch was, apparently ΓÇô I say ΓÇ£apparentlyΓÇ¥,
|
|
826
|
+
as I received no notification ΓÇô applied. By that time I had replaced the
|
|
827
827
|
whole mocking-and-stubbing subsystem and dropped the dependency.
|
|
828
828
|
|
|
829
829
|
Many Ruby developers claim that Ruby and its gems are too fast-moving for
|
|
830
830
|
normal package-managing systems to keep up. This is testament to the fact
|
|
831
|
-
that this isn
|
|
831
|
+
that this isnΓÇÖt the case and that the real problem is instead related to
|
|
832
832
|
sloppy practices.
|
|
833
833
|
|
|
834
|
-
Please note that I don
|
|
834
|
+
Please note that I donΓÇÖt want to single out the Mocha library nor its
|
|
835
835
|
developers. I only want to provide an example where relying on external
|
|
836
|
-
dependencies can be
|
|
836
|
+
dependencies can be ΓÇ£considered harmfulΓÇ¥.
|
|
837
837
|
|
|
838
|
-
|
|
839
|
-
|
|
838
|
+
┬╣ See the Wolfram Alpha calculation at http://www.wolframalpha.com/input/?i=days+between+march+17%2C+2010+and+november+26%2C+2010
|
|
839
|
+
┬▓ Check out the Wolfram Alpha computational knowledge engine at http://www.wolframalpha.com/
|
|
840
840
|
|
|
841
|
-
|
|
841
|
+
§ Internal Dependencies
|
|
842
842
|
|
|
843
843
|
Lookout has been designed so as to keep each subsystem independent of any
|
|
844
844
|
other. The diff subsystem is, for example, completely decoupled from any
|
|
845
845
|
other part of the system as a whole and could be moved into its own library
|
|
846
|
-
at a time where that would be of interest to anyone. What
|
|
846
|
+
at a time where that would be of interest to anyone. WhatΓÇÖs perhaps more
|
|
847
847
|
interesting is that the diff subsystem is itself very modular. The data
|
|
848
848
|
passes through a set of filters that depends on what kind of diff has been
|
|
849
849
|
requested, each filter yielding modified data as it receives it. If you
|
|
850
850
|
want to read some rather functional Ruby I can highly recommend looking at
|
|
851
|
-
the code in the
|
|
851
|
+
the code in the ‹lib/lookout/diff› directory.
|
|
852
852
|
|
|
853
853
|
This lookout on the design of the library also makes it easy to extend
|
|
854
854
|
Lookout. Lookout-rack was, for example, written in about four hours and
|
|
855
855
|
about 5 of those 240 minutes were spent on setting up the interface between
|
|
856
856
|
the two.
|
|
857
857
|
|
|
858
|
-
|
|
858
|
+
§ Optimizing For Speed
|
|
859
859
|
|
|
860
860
|
The following paragraph is perhaps a bit personal, but might be interesting
|
|
861
861
|
nonetheless.
|
|
862
862
|
|
|
863
|
-
I
|
|
864
|
-
|
|
865
|
-
used to hold the result of their execution (what we now term
|
|
863
|
+
IΓÇÖve always worried about speed. The original Expectations library used
|
|
864
|
+
‹extend› a lot to add new behavior to objects. Expectations, for example,
|
|
865
|
+
used to hold the result of their execution (what we now term ΓÇ£evaluationΓÇ¥)
|
|
866
866
|
by being extended by a module representing success, failure, or error. For
|
|
867
867
|
the longest time I used this same method, worrying about the increased
|
|
868
868
|
performance cost that creating new objects for results would incur. I
|
|
869
869
|
finally came to a point where I felt that the code was so simple and clean
|
|
870
|
-
that rewriting this part of the code for a benchmark wouldn
|
|
870
|
+
that rewriting this part of the code for a benchmark wouldnΓÇÖt take more
|
|
871
871
|
than perhaps ten minutes. Well, ten minutes later I had my results and
|
|
872
|
-
they confirmed that creating new objects wasn
|
|
872
|
+
they confirmed that creating new objects wasnΓÇÖt harming performance. I was
|
|
873
873
|
very pleased.
|
|
874
874
|
|
|
875
|
-
|
|
875
|
+
§ Naming
|
|
876
876
|
|
|
877
877
|
I hate low lines (underscores). I try to avoid them in method names and I
|
|
878
|
-
always avoid them in file names. Since the current
|
|
879
|
-
Ruby community is to put
|
|
880
|
-
|
|
878
|
+
always avoid them in file names. Since the current ΓÇ£best practiceΓÇ¥ in the
|
|
879
|
+
Ruby community is to put ‹BeginEndStorage› in a file called
|
|
880
|
+
‹begin_end_storage.rb›, I only name constants using a single noun. This
|
|
881
881
|
has had the added benefit that classes seem to have acquired less behavior,
|
|
882
|
-
as using a single noun doesn
|
|
883
|
-
without questioning if it
|
|
882
|
+
as using a single noun doesnΓÇÖt allow you to tack on additional behavior
|
|
883
|
+
without questioning if itΓÇÖs really appropriate to do so, given the rather
|
|
884
884
|
limited range of interpretation for that noun. It also seems to encourage
|
|
885
|
-
the creation of value objects, as something named
|
|
886
|
-
like a value than
|
|
885
|
+
the creation of value objects, as something named ‹Range› feels a lot more
|
|
886
|
+
like a value than ‹BeginEndStorage›. (To reach object-oriented-programming
|
|
887
887
|
Nirvana you must achieve complete value.)
|
|
888
888
|
|
|
889
|
-
|
|
889
|
+
§ News
|
|
890
890
|
|
|
891
|
-
|
|
891
|
+
§ 3.0.0
|
|
892
892
|
|
|
893
|
-
The
|
|
893
|
+
The ‹xml› expectation has been dropped. It wasn’t documented, didn’t
|
|
894
894
|
suit very many use cases, and can be better implemented by an external
|
|
895
895
|
library.
|
|
896
896
|
|
|
897
|
-
The
|
|
898
|
-
it didn
|
|
897
|
+
The ‹arg› argument matcher for mock method arguments has been removed, as
|
|
898
|
+
it didnΓÇÖt provide any benefit over using Object.
|
|
899
899
|
|
|
900
|
-
The
|
|
900
|
+
The ‹#yield› and ‹#each› methods on stub and mock methods have been
|
|
901
901
|
removed. They were slightly weird and their use case can be implemented
|
|
902
902
|
using block parameters instead.
|
|
903
903
|
|
|
904
|
-
The
|
|
904
|
+
The ‹stub› method inside ‹expect› blocks now stubs out the methods during
|
|
905
905
|
the execution of a provided block instead of during the execution of the
|
|
906
906
|
whole except block.
|
|
907
907
|
|
|
908
908
|
When a mock method is called too many times, this is reported
|
|
909
909
|
immediately, with a full backtrace. This makes it easier to pin down
|
|
910
|
-
what
|
|
910
|
+
whatΓÇÖs wrong with the code.
|
|
911
911
|
|
|
912
912
|
Query expectations were added.
|
|
913
913
|
|
|
914
914
|
Explicit query expectations were added.
|
|
915
915
|
|
|
916
|
-
Fluent boolean expectations, for example,
|
|
917
|
-
been replaced by query expectations (
|
|
918
|
-
explicit query expectations (
|
|
916
|
+
Fluent boolean expectations, for example, ‹expect nil.to.be.nil?› have
|
|
917
|
+
been replaced by query expectations (‹expect :nil? do nil end›) and
|
|
918
|
+
explicit query expectations (‹expect result.to.be.nil? do nil end›).
|
|
919
919
|
This was done to discourage creating objects as the expected value and
|
|
920
920
|
creating objects that change during the course of the test.
|
|
921
921
|
|
|
922
|
-
The
|
|
922
|
+
The ‹literal› expectation was added.
|
|
923
923
|
|
|
924
|
-
Equality (
|
|
924
|
+
Equality (‹#==›) is now checked before “caseity” (‹#===›) for modules,
|
|
925
925
|
ranges, and regular expressions to match the documentation.
|
|
926
926
|
|
|
927
|
-
|
|
927
|
+
§ Financing
|
|
928
928
|
|
|
929
929
|
Currently, most of my time is spent at my day job and in my rather busy
|
|
930
930
|
private life. Please motivate me to spend time on this piece of software
|
|
@@ -934,34 +934,38 @@ description: |2
|
|
|
934
934
|
to have other people give me the things that I need to continue living
|
|
935
935
|
under the rules of said society. So, if you feel that this piece of
|
|
936
936
|
software has helped you out enough to warrant a reward, please PayPal a
|
|
937
|
-
donation to now@disu.se
|
|
937
|
+
donation to now@disu.se┬╣. Thanks! Your support wonΓÇÖt go unnoticed!
|
|
938
938
|
|
|
939
|
-
|
|
940
|
-
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now%40disu%2ese&item_name=
|
|
939
|
+
┬╣ Send a donation:
|
|
940
|
+
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now%40disu%2ese&item_name=Lookout
|
|
941
941
|
|
|
942
|
-
|
|
942
|
+
§ Reporting Bugs
|
|
943
943
|
|
|
944
|
-
Please report any bugs that you encounter to the {issue tracker}
|
|
944
|
+
Please report any bugs that you encounter to the {issue tracker}┬╣.
|
|
945
945
|
|
|
946
|
-
|
|
946
|
+
┬╣ See https://github.com/now/lookout/issues
|
|
947
947
|
|
|
948
|
-
|
|
948
|
+
§ Contributors
|
|
949
949
|
|
|
950
950
|
Contributors to the original expectations codebase are mentioned there. We
|
|
951
951
|
hope no one on that list feels left out of this list. Please
|
|
952
|
-
{let us know}
|
|
952
|
+
{let us know}┬╣ if you do.
|
|
953
953
|
|
|
954
|
-
|
|
954
|
+
ΓÇó Nikolai Weibull
|
|
955
955
|
|
|
956
|
-
|
|
956
|
+
┬╣ Add an issue to the Lookout issue tracker at https://github.com/now/lookout/issues
|
|
957
957
|
|
|
958
|
-
|
|
958
|
+
§ Licensing
|
|
959
959
|
|
|
960
|
-
|
|
961
|
-
|
|
960
|
+
Lookout is free software: you may redistribute it and/or modify it under
|
|
961
|
+
the terms of the {GNU Lesser General Public License, version 3}┬╣ or later┬▓,
|
|
962
|
+
as published by the {Free Software Foundation}┬│.
|
|
962
963
|
|
|
963
|
-
|
|
964
|
-
|
|
964
|
+
┬╣ See http://disu.se/licenses/lgpl-3.0/
|
|
965
|
+
┬▓ See http://gnu.org/licenses/
|
|
966
|
+
┬│ See http://fsf.org/
|
|
967
|
+
email:
|
|
968
|
+
- now@disu.se
|
|
965
969
|
executables: []
|
|
966
970
|
extensions: []
|
|
967
971
|
extra_rdoc_files: []
|
|
@@ -1177,8 +1181,9 @@ files:
|
|
|
1177
1181
|
- test/unit/examples.rb
|
|
1178
1182
|
- README
|
|
1179
1183
|
- Rakefile
|
|
1180
|
-
homepage:
|
|
1181
|
-
licenses:
|
|
1184
|
+
homepage: http://disu.se/software/lookout
|
|
1185
|
+
licenses:
|
|
1186
|
+
- LGPLv3+
|
|
1182
1187
|
metadata: {}
|
|
1183
1188
|
post_install_message:
|
|
1184
1189
|
rdoc_options: []
|
|
@@ -1196,7 +1201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1196
1201
|
version: '0'
|
|
1197
1202
|
requirements: []
|
|
1198
1203
|
rubyforge_project:
|
|
1199
|
-
rubygems_version: 2.0.
|
|
1204
|
+
rubygems_version: 2.0.2
|
|
1200
1205
|
signing_key:
|
|
1201
1206
|
specification_version: 4
|
|
1202
1207
|
summary: focus.
|