rspec-given 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +167 -0
- data/Rakefile +38 -0
- data/examples/spec_helper.rb +2 -0
- data/examples/stack/stack.rb +25 -0
- data/examples/stack/stack_spec.rb +67 -0
- data/lib/rspec/given.rb +3 -0
- data/lib/rspec/given/extensions.rb +38 -0
- data/lib/rspec/given/version.rb +9 -0
- metadata +77 -0
data/README.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# rspec-given
|
2
|
+
|
3
|
+
rspec-given is an RSpec 2 extension to allow Given/When/Then notation
|
4
|
+
in RSpec specifications. It is a natural extension of the
|
5
|
+
experimental work done on the Given framework. It turns out that 90%
|
6
|
+
of the Given framework can be trivially implemented on top of RSpec.
|
7
|
+
|
8
|
+
# Why Given/When/Then
|
9
|
+
|
10
|
+
RSpec has done a great job of making specifications more readable for
|
11
|
+
humans. However, I really like the given / when / then nature of
|
12
|
+
Cucumber stories and would like to follow the same structure in my
|
13
|
+
unit tests. rspec-given allows a simple given/when/then structure
|
14
|
+
RSpec specifications.
|
15
|
+
|
16
|
+
## Status
|
17
|
+
|
18
|
+
rspec-given is quite usable at the moment, although is is lacking
|
19
|
+
several features.
|
20
|
+
|
21
|
+
* Invariants are not supported yet.
|
22
|
+
* Then assertions without _should_ are not supported yet.
|
23
|
+
|
24
|
+
## Example Zero
|
25
|
+
|
26
|
+
Here's the spec that I've been playing with. Its gone through
|
27
|
+
mulitple revisions and several prototype implementations. And this is
|
28
|
+
probably not the final form.
|
29
|
+
|
30
|
+
With all that in mind, here's a specification in my imaginary
|
31
|
+
framework:
|
32
|
+
|
33
|
+
<pre>
|
34
|
+
require 'spec_helper'
|
35
|
+
require 'stack'
|
36
|
+
|
37
|
+
describe Stack do
|
38
|
+
# NOTE: Invariants are not yet supported in rspec-given
|
39
|
+
# Invariant { stack.depth >= 0 }
|
40
|
+
# Invariant { stack.empty? == (stack.depth == 0) }
|
41
|
+
|
42
|
+
Given(:an_empty_stack) { Stack.new }
|
43
|
+
|
44
|
+
Given(:a_stack_with_one_item) do
|
45
|
+
Stack.new.tap do |s|
|
46
|
+
s.push(:an_item)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Given(:a_stack_with_several_items) do
|
51
|
+
Stack.new.tap do |s|
|
52
|
+
s.push(:second_item)
|
53
|
+
s.push(:top_item)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "an empty stack" do
|
58
|
+
Given(:stack) { an_empty_stack }
|
59
|
+
|
60
|
+
Then { stack.depth.should == 0 }
|
61
|
+
|
62
|
+
context "Pushing onto an empty stack" do
|
63
|
+
When { stack.push(:an_item) }
|
64
|
+
|
65
|
+
Then { stack.depth.should == 1 }
|
66
|
+
Then { stack.top.should == :an_item }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "a stack with one item do" do
|
71
|
+
Given(:stack) { a_stack_with_one_item }
|
72
|
+
|
73
|
+
context "popping an item empties the stack" do
|
74
|
+
When(:pop_result) { stack.pop }
|
75
|
+
|
76
|
+
Then { pop_result.should == :an_item }
|
77
|
+
Then { stack.should be_empty }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "a stack with several items" do
|
82
|
+
Given(:stack) { a_stack_with_several_items }
|
83
|
+
Given!(:original_depth) { stack.depth }
|
84
|
+
|
85
|
+
context "pushing a new item adds a new top" do
|
86
|
+
When { stack.push(:new_item) }
|
87
|
+
|
88
|
+
Then { stack.top.should == :new_item }
|
89
|
+
Then { stack.depth.should == original_depth + 1 }
|
90
|
+
end
|
91
|
+
|
92
|
+
context "popping an item removes the top item" do
|
93
|
+
When(:pop_result) { stack.pop }
|
94
|
+
|
95
|
+
Then { pop_result.should == :top_item }
|
96
|
+
Then { stack.top.should == :second_item }
|
97
|
+
Then { stack.depth.should == original_depth - 1 }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
</pre>
|
102
|
+
|
103
|
+
Let's talk about the individual sections.
|
104
|
+
|
105
|
+
### Given
|
106
|
+
|
107
|
+
The _Given_ section specifies a starting point, a set of preconditions
|
108
|
+
that must be true before the code under test is allowed to be run. In
|
109
|
+
standard test frameworks the preconditions are established with a
|
110
|
+
combination of setup methods (or :before actions in RSpec) and code in
|
111
|
+
the test.
|
112
|
+
|
113
|
+
In the example code above, we see three starting points of interest.
|
114
|
+
One is an empty, just freshly created stack. The next is a stack with
|
115
|
+
exactly one item. The final starting point is a stack with several
|
116
|
+
items.
|
117
|
+
|
118
|
+
A precondition in the form "Given(:var) {...}" creates an accessor
|
119
|
+
method named "var". The accessor is lazily initialized by the code
|
120
|
+
block. If you want a non-lazy given, use "Given!(:var) {...}".
|
121
|
+
|
122
|
+
A precondition in the form "Given {...}" just executes the code block
|
123
|
+
for side effects. Since there is no accessor, the code block is
|
124
|
+
executed immediately (i.e. no lazy evaluation).
|
125
|
+
|
126
|
+
The preconditions are run in order of definition. Nested contexts
|
127
|
+
will inherit the preconditions from the enclosing context, with out
|
128
|
+
preconditions running before inner preconditions.
|
129
|
+
|
130
|
+
### When
|
131
|
+
|
132
|
+
The _When_ block specifies the code to be tested ... oops, excuse me
|
133
|
+
... specified. After the preconditions in the given section are met,
|
134
|
+
the when code block is run.
|
135
|
+
|
136
|
+
There should only be one _When_ block for a given context.
|
137
|
+
|
138
|
+
### Then
|
139
|
+
|
140
|
+
The _Then_ sections are the postconditions of the specification. These
|
141
|
+
then conditions must be true after the code under test (the _When_
|
142
|
+
block) is run.
|
143
|
+
|
144
|
+
The code in the _Then_ block should be a single boolean condition that
|
145
|
+
devaluates to true if the code in the _When_ block is correct. If the
|
146
|
+
_Then_ block evaluates to false, then that is recorded as a failure.
|
147
|
+
|
148
|
+
### Invariant
|
149
|
+
|
150
|
+
The _Invariant_ block is a new idea that doesn't have an analog in
|
151
|
+
RSpec or Test::Unit. The invariant allows you specify things that
|
152
|
+
must always be true. In the stack example, <tt>empty?</tt> is defined
|
153
|
+
in term of <tt>size</tt>. Whenever <tt>size</tt> is 0,
|
154
|
+
<tt>empty?</tt> should be true. Whenever <tt>size</tt> is non-zero,
|
155
|
+
<tt>empty?</tt> should be false.
|
156
|
+
|
157
|
+
You can conceptually think of an _Invariant_ block as a _Then_ block
|
158
|
+
that automatically gets added to every _When_ within its scope.
|
159
|
+
|
160
|
+
Invariants nested within a context only apply to the _When_ blocks in
|
161
|
+
that context.
|
162
|
+
|
163
|
+
Invariants that reference a _Given_ precondition accessor must only be
|
164
|
+
used in contexts that define that accessor.
|
165
|
+
|
166
|
+
NOTE: Invariants are not yet implemented in the current version of
|
167
|
+
rspec-given.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/ruby -wKU
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
|
5
|
+
CLOBBER.include("*.gemspec", "html")
|
6
|
+
|
7
|
+
|
8
|
+
# README Formatting --------------------------------------------------
|
9
|
+
|
10
|
+
require 'bluecloth'
|
11
|
+
|
12
|
+
|
13
|
+
task :default => :examples
|
14
|
+
|
15
|
+
# Running examples ---------------------------------------------------
|
16
|
+
|
17
|
+
desc "Run the examples"
|
18
|
+
task :examples do
|
19
|
+
sh "rspec examples"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Formatting the README ----------------------------------------------
|
23
|
+
|
24
|
+
directory 'html'
|
25
|
+
|
26
|
+
desc "Display the README file"
|
27
|
+
task :readme => "html/README.html" do
|
28
|
+
sh "open html/README.html"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "format the README file"
|
32
|
+
task "html/README.html" => ['html', 'README.md'] do
|
33
|
+
open("README.md") do |source|
|
34
|
+
open('html/README.html', 'w') do |out|
|
35
|
+
out.write(BlueCloth.new(source.read).to_html)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Stack
|
2
|
+
def initialize
|
3
|
+
@items = []
|
4
|
+
end
|
5
|
+
|
6
|
+
def depth
|
7
|
+
@items.size
|
8
|
+
end
|
9
|
+
|
10
|
+
def empty?
|
11
|
+
@items.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def top
|
15
|
+
@items.last
|
16
|
+
end
|
17
|
+
|
18
|
+
def push(item)
|
19
|
+
@items << item
|
20
|
+
end
|
21
|
+
|
22
|
+
def pop
|
23
|
+
@items.pop
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stack'
|
3
|
+
|
4
|
+
describe Stack do
|
5
|
+
# NOTE: Invariants are not yet supported in rspec-given
|
6
|
+
# Invariant { stack.depth >= 0 }
|
7
|
+
# Invariant { stack.empty? == (stack.depth == 0) }
|
8
|
+
|
9
|
+
Given(:an_empty_stack) { Stack.new }
|
10
|
+
|
11
|
+
Given(:a_stack_with_one_item) do
|
12
|
+
Stack.new.tap do |s|
|
13
|
+
s.push(:an_item)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given(:a_stack_with_several_items) do
|
18
|
+
Stack.new.tap do |s|
|
19
|
+
s.push(:second_item)
|
20
|
+
s.push(:top_item)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "an empty stack" do
|
25
|
+
Given(:stack) { an_empty_stack }
|
26
|
+
|
27
|
+
Then { stack.depth.should == 0 }
|
28
|
+
|
29
|
+
context "Pushing onto an empty stack" do
|
30
|
+
When { stack.push(:an_item) }
|
31
|
+
|
32
|
+
Then { stack.depth.should == 1 }
|
33
|
+
Then { stack.top.should == :an_item }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "a stack with one item do" do
|
38
|
+
Given(:stack) { a_stack_with_one_item }
|
39
|
+
|
40
|
+
context "popping an item empties the stack" do
|
41
|
+
When(:pop_result) { stack.pop }
|
42
|
+
|
43
|
+
Then { pop_result.should == :an_item }
|
44
|
+
Then { stack.should be_empty }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "a stack with several items" do
|
49
|
+
Given(:stack) { a_stack_with_several_items }
|
50
|
+
Given!(:original_depth) { stack.depth }
|
51
|
+
|
52
|
+
context "pushing a new item adds a new top" do
|
53
|
+
When { stack.push(:new_item) }
|
54
|
+
|
55
|
+
Then { stack.top.should == :new_item }
|
56
|
+
Then { stack.depth.should == original_depth + 1 }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "popping an item removes the top item" do
|
60
|
+
When(:pop_result) { stack.pop }
|
61
|
+
|
62
|
+
Then { pop_result.should == :top_item }
|
63
|
+
Then { stack.top.should == :second_item }
|
64
|
+
Then { stack.depth.should == original_depth - 1 }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/rspec/given.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rspec/core/let'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
class ExampleGroup
|
6
|
+
alias_example_to :Then
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module RSpec
|
12
|
+
module Core
|
13
|
+
module Let
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def Given(*args,&block)
|
17
|
+
if args.first.is_a?(Symbol)
|
18
|
+
let(args.first, &block)
|
19
|
+
else
|
20
|
+
before(&block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def Given!(var, &block)
|
25
|
+
let!(var, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def When(*args, &block)
|
29
|
+
if args.first.is_a?(Symbol)
|
30
|
+
let!(args.first, &block)
|
31
|
+
else
|
32
|
+
before(&block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-given
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jim Weirich
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-27 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: |
|
22
|
+
Given is an RSpec extension that allows explicit definition of the
|
23
|
+
pre and post-conditions for code under test.
|
24
|
+
|
25
|
+
email: jim.weirich@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- Rakefile
|
34
|
+
- README.md
|
35
|
+
- lib/rspec/given/extensions.rb
|
36
|
+
- lib/rspec/given/version.rb
|
37
|
+
- lib/rspec/given.rb
|
38
|
+
- examples/spec_helper.rb
|
39
|
+
- examples/stack/stack.rb
|
40
|
+
- examples/stack/stack_spec.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/jimweirich/rspec-given
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options:
|
47
|
+
- --line-numbers
|
48
|
+
- --inline-source
|
49
|
+
- --main
|
50
|
+
- README.md
|
51
|
+
- --title
|
52
|
+
- RSpec Given Extensions
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: given
|
72
|
+
rubygems_version: 1.3.6
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Given/When/Then Specification Extensions for RSpec.
|
76
|
+
test_files: []
|
77
|
+
|