rspec-given 1.0.0
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.
- 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
|
+
|