rspec-given 2.3.0.beta.3 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +112 -42
- data/examples/failing/natural_failing_spec.rb +12 -0
- data/lib/rspec/given/configure.rb +2 -0
- data/lib/rspec/given/extensions.rb +2 -2
- data/lib/rspec/given/failure.rb +21 -1
- data/lib/rspec/given/fuzzy_number.rb +64 -0
- data/lib/rspec/given/have_failed.rb +12 -0
- data/lib/rspec/given/version.rb +0 -2
- metadata +6 -5
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rspec-given
|
2
2
|
|
3
|
-
Covering rspec-given, version 2.3.0.
|
3
|
+
Covering rspec-given, version 2.3.0.
|
4
4
|
|
5
5
|
rspec-given is an RSpec extension to allow Given/When/Then notation in
|
6
6
|
RSpec specifications. It is a natural extension of the experimental
|
@@ -305,14 +305,19 @@ stick with _Then_ clauses.
|
|
305
305
|
|
306
306
|
The _Invariant_ clause is a new idea that doesn't have an analog in
|
307
307
|
RSpec or Test::Unit. The invariant allows you specify things that must
|
308
|
-
always be true in the scope of the invariant. In the stack example,
|
309
|
-
<tt>empty?</tt> is defined in term of <tt>size</tt>.
|
310
|
-
|
311
|
-
|
308
|
+
always be true in the scope of the invariant. In the stack example, the method
|
309
|
+
<tt>empty?</tt> is defined in term of <tt>size</tt>.
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
Invariant { stack.empty? == (stack.depth == 0) }
|
313
|
+
```
|
314
|
+
|
315
|
+
This invariant states that <code>empty?</code> is true if and only if
|
316
|
+
the stack depth is zero, and that assertion is checked at every _Then_
|
317
|
+
clause that is in the same scope.
|
312
318
|
|
313
319
|
You can conceptually think of an _Invariant_ clause as a _Then_ block
|
314
320
|
that automatically gets added to every _Then_ within its scope.
|
315
|
-
|
316
321
|
Invariants nested within a context only apply to the _Then_ clauses
|
317
322
|
that are in the scope of that context.
|
318
323
|
|
@@ -325,10 +330,40 @@ Notes:
|
|
325
330
|
represented in the RSpec formatted output (e.g. the '--format html'
|
326
331
|
option).
|
327
332
|
|
333
|
+
## Execution Ordering
|
334
|
+
|
335
|
+
When running the test for a specific _Then_ clause, the following will
|
336
|
+
be true:
|
337
|
+
|
338
|
+
* The _Given_ clauses will be run in the order that they are
|
339
|
+
specified, from the outermost scope to the innermost scope
|
340
|
+
containing the _Then_.
|
341
|
+
|
342
|
+
* All of the _Given_ clauses in all of the relevant scopes will run
|
343
|
+
before the first (outermost) _When_ clause in those same scopes.
|
344
|
+
That means that the _When_ code can assume that the givens have been
|
345
|
+
established, even if the givens are in a more nested scope than the
|
346
|
+
When.
|
347
|
+
|
348
|
+
* _When_ clauses and RSpec _before_ blocks will be executed in the
|
349
|
+
order that they are specified, from the outermost block to the
|
350
|
+
innermost block. This makes _before_ blocks an excellent choice
|
351
|
+
when writing narrative tests to specify actions that happen between
|
352
|
+
the "whens" of a narrative.
|
353
|
+
|
354
|
+
Note that the ordering between _Given_ clauses and _before_ blocks are
|
355
|
+
a not strongly specified. Hoisting a _When_ clause out of an inner
|
356
|
+
scope to an outer scope may change the ordering of when the _Given_
|
357
|
+
clause runs in relation to a _before_ block (the hoisting will cause
|
358
|
+
the givens to possibly run earlier). Because of this, do not split
|
359
|
+
order dependent code between _Given_ clauses and _before_ blocks.
|
360
|
+
|
328
361
|
## Natural Assertions
|
329
362
|
|
330
363
|
**NOTE:** <em>Natural assertions are an experimental feature of
|
331
|
-
RSpec/Given. They are currently disabled by default
|
364
|
+
RSpec/Given. They are currently disabled by default. They can be
|
365
|
+
enabled by a simple configuration option (see "use_natural_assertions"
|
366
|
+
below).</em>
|
332
367
|
|
333
368
|
RSpec/Given now supports the use of "natural assertions" in _Then_,
|
334
369
|
_And_, and _Invariant_ blocks. Natural assertions are just Ruby
|
@@ -399,12 +434,14 @@ Keep the following in mind when using Natural Assertions.
|
|
399
434
|
to join the conditions into a single expression (and the failure
|
400
435
|
message will breakdown the values for each part).
|
401
436
|
|
402
|
-
*
|
403
|
-
|
437
|
+
* Then clauses need be **idempotent**. This is true in general, but it
|
438
|
+
is particularly important for Natural assertions to obey this
|
439
|
+
restriction. This means that assertions in a Then clause should not
|
440
|
+
change anything. Since the natural assertion error message contains
|
404
441
|
the values of all the subexpressions, the expression and its
|
405
|
-
subexpressions will be evaluated multiple times. If the
|
406
|
-
idempotent, you will get changing answers as the
|
407
|
-
evaluated.
|
442
|
+
subexpressions will be evaluated multiple times. If the Then clause
|
443
|
+
is not idempotent, you will get changing answers as the
|
444
|
+
subexpressions are evaluated.
|
408
445
|
|
409
446
|
That last point is important. If you write code like this:
|
410
447
|
|
@@ -433,6 +470,9 @@ like this is good:
|
|
433
470
|
end
|
434
471
|
```
|
435
472
|
|
473
|
+
It is good to note that non-idempotent assertions will also cause
|
474
|
+
problems with And clauses.
|
475
|
+
|
436
476
|
### Mixing Natural Assertions and RSpec Assertions
|
437
477
|
|
438
478
|
Natural assertions and RSpec assertions for the most part can be
|
@@ -463,49 +503,79 @@ will not process natural assertions.
|
|
463
503
|
See the **configuration** section below to see how to enable natural
|
464
504
|
assertions project wide.
|
465
505
|
|
466
|
-
###
|
506
|
+
### Matchers and Natural Assertions
|
467
507
|
|
468
|
-
|
508
|
+
In RSpec, matchers are used to provide nice, readable error messages
|
509
|
+
when an assertion is not met. Natural assertions provide
|
510
|
+
self-explanatory failure messages for most things without requiring
|
511
|
+
any special matchers from the programmer.
|
469
512
|
|
470
|
-
|
471
|
-
|
513
|
+
In the rare case that some extra information would be hepful, it is
|
514
|
+
useful to create special objects that respond to the == operator.
|
472
515
|
|
473
|
-
|
474
|
-
assertion and don't need a failure message).
|
516
|
+
#### Asserting Nearly Equal
|
475
517
|
|
476
|
-
|
477
|
-
|
518
|
+
Operations on floating point numbers rarely create numbers that are
|
519
|
+
exactly equal, therefore it is useful to assert that two floating
|
520
|
+
point numbers are nearly equal.
|
478
521
|
|
479
|
-
|
480
|
-
|
481
|
-
possible to correctly determine if _should_ and _expect_ are used
|
482
|
-
merely from the source. Fortunately you can always override the
|
483
|
-
automatic detection by either forcing natural assertions (with
|
484
|
-
:always) or disabling them (with false).
|
522
|
+
For example, the following asserts that the square root of 10 is about
|
523
|
+
3.1523 with an accuracy of 0.1 percent.
|
485
524
|
|
486
525
|
```ruby
|
487
|
-
|
488
|
-
context "sample" do
|
489
|
-
use_natural_assertions :always
|
490
|
-
Then { obj.should } # Non-rspec should is called
|
491
|
-
end
|
526
|
+
Then { Math.sqrt(10) == about(3.1623).percent(1) }
|
492
527
|
```
|
493
528
|
|
529
|
+
As long as the real value of <code>Math.sqrt(10)</code> is within plus
|
530
|
+
or minus 1% of 3.1623 (i.e. 3.1623 +/- 0.0031623), then the assertion
|
531
|
+
will pass.
|
532
|
+
|
533
|
+
There are several ways of creating approximate numbers:
|
534
|
+
|
535
|
+
* <code>about(n).delta(d)</code> -- A fuzzy number matching the range
|
536
|
+
(n-d)..(n+d)
|
537
|
+
|
538
|
+
* <code>about(n).percent(p)</code> -- A fuzzy number matching the
|
539
|
+
range (n-(n*p/100)) .. (n+(n*p/100))
|
540
|
+
|
541
|
+
* <code>about(n).epsilon(neps)</code> -- A fuzzy number matching the
|
542
|
+
range (n-(neps*e)) .. (n+(neps*e)), where e is the difference
|
543
|
+
between 1.0 and the next smallest floating point number.
|
544
|
+
|
545
|
+
* <code>about(n)</code> -- Same as <code>about(n).epsilon(10)</code>.
|
546
|
+
|
547
|
+
#### Detecting Exceptions
|
548
|
+
|
549
|
+
The RSpec matcher used for detecting exceptions will work with natural
|
550
|
+
assertions out of the box. Just check for equality against the
|
551
|
+
<code>have_failed</code> return value.
|
552
|
+
|
553
|
+
For example, the following two Then clauses are equivalent:
|
554
|
+
|
494
555
|
```ruby
|
495
|
-
|
496
|
-
|
497
|
-
use_natural_assertions false
|
498
|
-
Then { check_validations(obj) } # check_validations calls "should" internally
|
499
|
-
end
|
556
|
+
# Using an RSpec matcher
|
557
|
+
Then { result.should have_failed(StandardError, /message/) }
|
500
558
|
|
501
|
-
|
502
|
-
|
503
|
-
it "checks validations" do
|
504
|
-
check_validations(obj)
|
505
|
-
end
|
506
|
-
end
|
559
|
+
# Using natural assertions
|
560
|
+
Then { result == have_failed(StandardError, /message/) }
|
507
561
|
```
|
508
562
|
|
563
|
+
### Processing Natural Assertions
|
564
|
+
|
565
|
+
When natural assertions are enabled, they are only used if:
|
566
|
+
|
567
|
+
1. The block does not throw an RSpec assertion failure (or any other
|
568
|
+
exception for that matter).
|
569
|
+
|
570
|
+
1. The block returns false (blocks that return true pass the
|
571
|
+
assertion and don't need a failure message).
|
572
|
+
|
573
|
+
1. The block does not use RSpec's _should_ or _expect_ methods.
|
574
|
+
|
575
|
+
Detecting that last point (the use of _should_ and _expect_) is done
|
576
|
+
by modifying the RSpec runtime to report uses of _should_ and
|
577
|
+
_expect_.
|
578
|
+
|
509
579
|
### Further Reading
|
510
580
|
|
511
581
|
Natural assertions were inspired by the [wrong assertion
|
@@ -23,6 +23,18 @@ describe "Natural Assertions" do
|
|
23
23
|
(puts "Ha ha world", ! true)
|
24
24
|
}
|
25
25
|
|
26
|
+
Then { Math.sqrt(10) == about(3.1623).percent(0.0001) }
|
27
|
+
|
28
|
+
describe "Error Examples" do
|
29
|
+
When(:result) { fail "OUCH" }
|
30
|
+
Then { result == :ok }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "Non-Error Failures" do
|
34
|
+
When(:result) { :ok }
|
35
|
+
Then { result == have_failed(StandardError, /^O/) }
|
36
|
+
end
|
37
|
+
|
26
38
|
context "Incorrect non-idempotent conditions" do
|
27
39
|
Given(:ary) { [1, 2, 3] }
|
28
40
|
Then { ary.delete(1) == nil }
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'rspec/given/extensions'
|
3
|
+
require 'rspec/given/fuzzy_number'
|
3
4
|
require 'rspec/given/have_failed'
|
4
5
|
require 'rspec/given/module_methods'
|
5
6
|
|
@@ -7,6 +8,7 @@ RSpec.configure do |c|
|
|
7
8
|
c.extend(RSpec::Given::ClassExtensions)
|
8
9
|
c.include(RSpec::Given::InstanceExtensions)
|
9
10
|
c.include(RSpec::Given::HaveFailed)
|
11
|
+
c.include(RSpec::Given::Fuzzy)
|
10
12
|
|
11
13
|
c.backtrace_clean_patterns << /lib\/rspec\/given/
|
12
14
|
|
@@ -159,7 +159,7 @@ module RSpec
|
|
159
159
|
# Scenario "a scenario description" do ... end
|
160
160
|
#
|
161
161
|
def Scenario(description, &block)
|
162
|
-
file, line = eval("[
|
162
|
+
file, line = eval("[__FILE__, __LINE__]", block.binding)
|
163
163
|
puts "WARNING: Scenario is deprecated, please use either describe or context (#{file}:#{line})"
|
164
164
|
context(description, &block)
|
165
165
|
end
|
@@ -190,7 +190,7 @@ module RSpec
|
|
190
190
|
# Given!(:name) { ... code ... }
|
191
191
|
#
|
192
192
|
def Given!(name, &block)
|
193
|
-
let
|
193
|
+
let(name, &block)
|
194
194
|
_rgc_givens << _rgc_trigger_given(name)
|
195
195
|
end
|
196
196
|
|
data/lib/rspec/given/failure.rb
CHANGED
@@ -14,9 +14,29 @@ module RSpec
|
|
14
14
|
klass == Failure
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def ==(other)
|
18
|
+
if other.is_a?(::RSpec::Given::HaveFailed::HaveFailedMatcher)
|
19
|
+
other.matches?(self)
|
20
|
+
else
|
21
|
+
die
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def !=(other)
|
26
|
+
if other.is_a?(::RSpec::Given::HaveFailed::HaveFailedMatcher)
|
27
|
+
! other.matches?(self)
|
28
|
+
else
|
29
|
+
die
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def die
|
18
34
|
::Kernel.raise @exception
|
19
35
|
end
|
36
|
+
|
37
|
+
def method_missing(sym, *args, &block)
|
38
|
+
die
|
39
|
+
end
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module RSpec
|
3
|
+
module Given
|
4
|
+
module Fuzzy
|
5
|
+
class FuzzyNumber
|
6
|
+
|
7
|
+
DEFAULT_EPSILON = 10 * Float::EPSILON
|
8
|
+
|
9
|
+
attr_reader :exact_value, :delta_amount
|
10
|
+
|
11
|
+
def initialize(exact_value)
|
12
|
+
@exact_value = exact_value
|
13
|
+
@delta_amount = exact_value * DEFAULT_EPSILON
|
14
|
+
end
|
15
|
+
|
16
|
+
# Low limit of the fuzzy number.
|
17
|
+
def low_limit
|
18
|
+
exact_value - delta_amount
|
19
|
+
end
|
20
|
+
|
21
|
+
# High limit of the fuzzy number.
|
22
|
+
def high_limit
|
23
|
+
exact_value + delta_amount
|
24
|
+
end
|
25
|
+
|
26
|
+
# True if the other number is in range of the fuzzy number.
|
27
|
+
def ==(other)
|
28
|
+
(other - exact_value).abs <= delta_amount
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"<Approximately #{exact_value} +/- #{delta_amount}>"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the delta for a fuzzy number.
|
36
|
+
def delta(delta)
|
37
|
+
@delta_amount = delta.abs
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Specifying a percentage of the exact number to be used in
|
42
|
+
# setting the delta.
|
43
|
+
def percent(percentage)
|
44
|
+
delta(exact_value * (percentage / 100.0))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Specifying the number of epsilons to be used in setting the
|
48
|
+
# delta.
|
49
|
+
def epsilon(neps)
|
50
|
+
delta(exact_value * (neps * Float::EPSILON))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create an approximate number that is approximately equal to
|
55
|
+
# the given number, plus or minus the delta value. If no
|
56
|
+
# explicit delta is given, then the default delta that is about
|
57
|
+
# 10X the size of the smallest possible change in the given
|
58
|
+
# number will be used.
|
59
|
+
def about(*args)
|
60
|
+
FuzzyNumber.new(*args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -24,6 +24,10 @@ module RSpec
|
|
24
24
|
super(lambda { })
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"<Failure matching #{@expected_error}: #{@expected_message.inspect}>"
|
30
|
+
end
|
27
31
|
end
|
28
32
|
|
29
33
|
else
|
@@ -36,6 +40,10 @@ module RSpec
|
|
36
40
|
super(lambda { })
|
37
41
|
end
|
38
42
|
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"<FailureMatcher on #{@expected_error}: #{@expected_message.inspect}>"
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
end
|
@@ -58,6 +66,10 @@ module RSpec
|
|
58
66
|
def have_failed(error=Exception, message=nil, &block)
|
59
67
|
HaveFailedMatcher.new(error, message, &block)
|
60
68
|
end
|
69
|
+
alias have_raised have_failed
|
70
|
+
|
71
|
+
def failure(error=Exception, message=nil, &block)
|
72
|
+
end
|
61
73
|
end
|
62
74
|
end
|
63
75
|
end
|
data/lib/rspec/given/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-given
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.0
|
5
|
-
prerelease:
|
4
|
+
version: 2.3.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jim Weirich
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- lib/rspec/given/extensions.rb
|
113
113
|
- lib/rspec/given/failure.rb
|
114
114
|
- lib/rspec/given/file_cache.rb
|
115
|
+
- lib/rspec/given/fuzzy_number.rb
|
115
116
|
- lib/rspec/given/have_failed.rb
|
116
117
|
- lib/rspec/given/line_extractor.rb
|
117
118
|
- lib/rspec/given/module_methods.rb
|
@@ -153,9 +154,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
155
|
none: false
|
155
156
|
requirements:
|
156
|
-
- - ! '
|
157
|
+
- - ! '>='
|
157
158
|
- !ruby/object:Gem::Version
|
158
|
-
version:
|
159
|
+
version: '0'
|
159
160
|
requirements: []
|
160
161
|
rubyforge_project: given
|
161
162
|
rubygems_version: 1.8.24
|