specify 0.10.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +46 -26
- data/.hound.yml +38 -55
- data/.rspec +3 -0
- data/.rubocop.yml +4 -0
- data/.travis.yml +7 -11
- data/CODE_OF_CONDUCT.md +68 -7
- data/Gemfile +5 -1
- data/LICENSE.md +21 -0
- data/README.md +153 -27
- data/Rakefile +11 -7
- data/bin/console +3 -6
- data/bin/setup +4 -1
- data/lib/specify.rb +36 -47
- data/lib/specify/rspec/example_group.rb +47 -40
- data/lib/specify/rspec/formatter.rb +72 -0
- data/lib/specify/rspec/notification.rb +0 -3
- data/lib/specify/rspec/reporter.rb +8 -15
- data/lib/specify/rspec/shared_steps.rb +1 -3
- data/lib/specify/rspec/world.rb +0 -3
- data/lib/specify/spec.rb +23 -17
- data/lib/specify/version.rb +1 -1
- data/specify.gemspec +26 -33
- metadata +46 -22
- data/LICENSE.txt +0 -22
- data/lib/specify/rspec/documentation_formatter.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d8d284ca6600d067bcd67451cb6af8abef30831d25d1b2d5a1e9b4fe4619f127
|
4
|
+
data.tar.gz: 20b23de09742a461528a04df263b68ff11ddd0efcda66231242caa4f2efe71e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e74dad48ac6b8216a2d47f038fa65a9769c46e001e921be9f02982f0e1bd5f9903b4b20dd073cb39f3c30698d87b792eed7609b5ddff778af2ee8308d18d9917
|
7
|
+
data.tar.gz: c5ff56f667afa59729bfc8a4c802794d0266233c4c72ec2fff8c8d6e93a4ade47beb3c37d59227479375e1130f534464dc42c2a3e66a5c95cda0c1ed51a73315
|
data/.gitignore
CHANGED
@@ -1,29 +1,49 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
1
|
+
# Ruby Generated
|
2
|
+
|
3
|
+
/Gemfile.lock
|
4
|
+
/.bundle/
|
5
|
+
/.yardoc
|
6
|
+
/_yardoc/
|
7
|
+
/coverage/
|
8
|
+
/doc/
|
9
|
+
/pkg/
|
10
|
+
/spec/reports/
|
11
|
+
/spec/coverage/
|
12
|
+
/tmp/
|
13
|
+
|
14
|
+
# Generated Reports
|
15
|
+
reports/
|
16
|
+
|
17
|
+
# Rspec Failure Tracking
|
18
|
+
|
19
|
+
.rspec_status
|
20
|
+
|
21
|
+
# IDE Files
|
22
|
+
|
23
|
+
.idea/
|
24
|
+
*.iml
|
25
|
+
*.iws
|
26
|
+
*.ipr
|
27
|
+
.vscode/
|
28
|
+
.settings/
|
29
|
+
.metadata
|
30
|
+
.classpath
|
31
|
+
.loadpath
|
32
|
+
.buildpath
|
33
|
+
.project
|
34
|
+
|
35
|
+
# OS Files
|
36
|
+
|
26
37
|
.DS_Store
|
27
38
|
.DS_Store?
|
39
|
+
._*
|
40
|
+
.Spotlight-V100
|
28
41
|
.Trashes
|
29
|
-
.
|
42
|
+
ehthumbs.db
|
43
|
+
Thumbs.db
|
44
|
+
$RECYCLE.BIN/
|
45
|
+
Desktop.ini
|
46
|
+
*.tmp
|
47
|
+
*.bak
|
48
|
+
*.swp
|
49
|
+
*~.nib
|
data/.hound.yml
CHANGED
@@ -1,95 +1,78 @@
|
|
1
1
|
AllCops:
|
2
2
|
Exclude:
|
3
3
|
- specify.gemspec
|
4
|
-
- test/*.rb
|
5
4
|
- spec/**/*
|
6
5
|
|
7
|
-
#
|
6
|
+
# Removing need for frozen string literal comment.
|
7
|
+
Style/FrozenStringLiteralComment:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
# Removing the preference for string single quotes.
|
11
|
+
Style/StringLiterals:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
# Missing top-level module documentation comment.
|
8
15
|
Style/Documentation:
|
9
16
|
Enabled: false
|
10
17
|
|
11
|
-
#
|
18
|
+
# Prefer reduce over inject.
|
12
19
|
Style/CollectionMethods:
|
13
20
|
PreferredMethods:
|
14
21
|
reduce: 'inject'
|
15
22
|
|
16
|
-
#
|
23
|
+
# Use each_with_object instead of inject.
|
17
24
|
Style/EachWithObject:
|
18
25
|
Enabled: false
|
19
26
|
|
20
|
-
#
|
21
|
-
Style/StringLiterals:
|
22
|
-
Enabled: false
|
23
|
-
|
24
|
-
# prefer fail over raise
|
27
|
+
# Prefer fail over raise.
|
25
28
|
Style/SignalException:
|
26
29
|
Enabled: false
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# this never works for validations
|
32
|
-
Style/AlignHash:
|
31
|
+
# This never works for validations.
|
32
|
+
Layout/AlignHash:
|
33
33
|
EnforcedLastArgumentHashStyle: ignore_implicit
|
34
34
|
|
35
|
-
#
|
36
|
-
|
35
|
+
# Align multi-line params with previous line.
|
36
|
+
Layout/AlignParameters:
|
37
37
|
EnforcedStyle: with_fixed_indentation
|
38
38
|
|
39
|
-
#
|
40
|
-
|
39
|
+
# Indent `when` clause one step from `case`.
|
40
|
+
Layout/CaseIndentation:
|
41
41
|
IndentOneStep: true
|
42
42
|
|
43
|
-
#
|
43
|
+
# Don't force bad var names for reduce/inject loops.
|
44
44
|
Style/SingleLineBlockParams:
|
45
45
|
Enabled: false
|
46
46
|
|
47
|
-
#
|
48
|
-
|
47
|
+
# For method chains, keep the dot with the method name.
|
48
|
+
Layout/DotPosition:
|
49
49
|
EnforcedStyle: leading
|
50
50
|
|
51
|
-
|
52
|
-
Enabled: false
|
53
|
-
|
54
|
-
Style/PredicateName:
|
55
|
-
Enabled: false
|
56
|
-
|
57
|
-
Style/MethodName:
|
58
|
-
Enabled: false
|
59
|
-
|
60
|
-
Style/Alias:
|
61
|
-
Enabled: false
|
62
|
-
|
63
|
-
Style/Next:
|
64
|
-
Enabled: false
|
65
|
-
|
66
|
-
# stop nesting so hard
|
51
|
+
# Stop nesting so hard.
|
67
52
|
Metrics/BlockNesting:
|
68
53
|
Max: 2
|
69
54
|
|
70
|
-
# short methods
|
55
|
+
# Encourage short methods.
|
71
56
|
Metrics/MethodLength:
|
72
|
-
Max:
|
57
|
+
Max: 15
|
73
58
|
|
74
|
-
|
75
|
-
|
76
|
-
|
59
|
+
# Encourage short (as possible) modules.
|
60
|
+
Metrics/ModuleLength:
|
61
|
+
Max: 100
|
77
62
|
|
78
|
-
# fewer parameters
|
63
|
+
# Encourage fewer parameters.
|
79
64
|
Metrics/ParameterLists:
|
80
|
-
Max:
|
65
|
+
Max: 4
|
81
66
|
|
82
|
-
|
67
|
+
# Remove execute permissions check.
|
68
|
+
Lint/ScriptPermission:
|
83
69
|
Enabled: false
|
84
70
|
|
85
|
-
|
86
|
-
Max: 130
|
87
|
-
|
88
|
-
Metrics/CyclomaticComplexity:
|
89
|
-
Max: 12
|
71
|
+
# Specify Additions
|
90
72
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
73
|
+
# This checks assignments, branches and coverage. During development,
|
74
|
+
# adding to the output of RSpec in a way that reads cleanly as code
|
75
|
+
# means being a little only slightly more forgiving for this metric.
|
76
|
+
# The default value is 15.
|
77
|
+
Metrics/AbcSize:
|
78
|
+
Max: 17
|
data/.rspec
ADDED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
---
|
3
2
|
sudo: false
|
3
|
+
language: ruby
|
4
|
+
cache: bundler
|
4
5
|
|
5
6
|
rvm:
|
6
|
-
- 2.
|
7
|
-
|
8
|
-
|
7
|
+
- 2.5.1
|
8
|
+
|
9
|
+
before_install:
|
10
|
+
- gem install bundler
|
9
11
|
|
10
12
|
branches:
|
11
13
|
only:
|
12
14
|
- master
|
13
|
-
|
14
|
-
notifications:
|
15
|
-
recipients:
|
16
|
-
- jeffnyman@gmail.com
|
17
|
-
|
18
|
-
before_install: gem install bundler -v 1.10.6
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -1,13 +1,74 @@
|
|
1
|
-
# Contributor Code of Conduct
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
2
|
|
3
|
-
|
3
|
+
## Our Pledge
|
4
4
|
|
5
|
-
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
6
11
|
|
7
|
-
|
12
|
+
## Our Standards
|
8
13
|
|
9
|
-
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
10
16
|
|
11
|
-
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
12
22
|
|
13
|
-
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at jeff.nyman@yello.co. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
CHANGED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Jeff Nyman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,25 +1,22 @@
|
|
1
1
|
# Specify
|
2
2
|
|
3
|
-
|
3
|
+
> **The height of sophistication is simplicity.**<br>
|
4
|
+
> *Clare Boothe Brokaw*
|
4
5
|
|
5
|
-
[![Coverage Status](https://img.shields.io/coveralls/jnyman/specify.svg)](https://coveralls.io/r/jnyman/specify?branch=master)
|
6
6
|
[![Gem Version](https://badge.fury.io/rb/specify.svg)](http://badge.fury.io/rb/specify)
|
7
|
-
[![
|
8
|
-
[![
|
7
|
+
[![Build Status](https://travis-ci.org/jeffnyman/specify.svg)](https://travis-ci.org/jeffnyman/specify)
|
8
|
+
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jeffnyman/specify/blob/master/LICENSE.md)
|
9
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/a42684de1702ed5a9333/maintainability)](https://codeclimate.com/github/jeffnyman/specify/maintainability)
|
9
10
|
|
10
|
-
|
11
|
-
[![endorse](https://api.coderwall.com/jnyman/endorsecount.png)](https://coderwall.com/jnyman)
|
11
|
+
---
|
12
12
|
|
13
|
-
|
14
|
-
> -- <cite>Leonardo da Vinci</cite>
|
13
|
+
Specify is a tool for leveraging RSpec to create an expressive DSL for test and data conditions. Specify will also provide test result reporting that recognizes the DSL.
|
15
14
|
|
16
|
-
Specify
|
17
|
-
|
18
|
-
Specify provides a very thin wrapper around RSpec that provides a Gherkin-style syntax for use with test examples.
|
15
|
+
Specify provides an internal DSL, similar to the [RSpec Story Runner](https://github.com/dchelimsky/rspec-stories). This was the predecessor of the [Cucumber](http://cukes.info/) external DSL provided by [Gherkin](http://cukes.info/gherkin.html).
|
19
16
|
|
20
17
|
## Installation
|
21
18
|
|
22
|
-
|
19
|
+
Add this line to your application's Gemfile:
|
23
20
|
|
24
21
|
```ruby
|
25
22
|
gem 'specify'
|
@@ -28,45 +25,173 @@ gem 'specify'
|
|
28
25
|
To get the latest code:
|
29
26
|
|
30
27
|
```ruby
|
31
|
-
gem 'specify', git: https://github.com/
|
28
|
+
gem 'specify', git: 'https://github.com/jeffnyman/specify'
|
32
29
|
```
|
33
30
|
|
34
31
|
After doing one of the above, execute the following command:
|
35
32
|
|
36
|
-
|
33
|
+
```
|
34
|
+
$ bundle
|
35
|
+
```
|
37
36
|
|
38
37
|
You can also install Specify just as you would any other gem:
|
39
38
|
|
40
|
-
|
39
|
+
```
|
40
|
+
$ gem install specify
|
41
|
+
```
|
41
42
|
|
42
43
|
## Usage
|
43
44
|
|
44
|
-
To use Specify you simply have to require it within your `spec_helper` file:
|
45
|
+
To use Specify you simply have to require it within your `spec_helper.rb` file:
|
45
46
|
|
46
47
|
```ruby
|
47
48
|
require 'specify'
|
48
49
|
```
|
49
50
|
|
50
|
-
|
51
|
+
Because Specify uses a custom formatter, you should have an `.rspec` file with the following line in it:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
--format RSpec::Specify::Formatter
|
55
|
+
```
|
56
|
+
|
57
|
+
Then you simply run your `rspec` command as normal against your test suite. Where the Specify formatter comes into play is in how you can construct your test specifications. You can use RSpec constructs within Specify constructs. Here is an example:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Feature 'Bank Accounts' do
|
61
|
+
let(:valid_account_number) { '1234567890' }
|
62
|
+
subject { Account.new(valid_account_number) }
|
63
|
+
|
64
|
+
Scenario 'starting a new account' do
|
65
|
+
test 'will have a starting balance of 0' do
|
66
|
+
expect(subject.balance).to eq(0)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'will not allow an invalid account name' do
|
70
|
+
expect { Account.new('thx1138') }.to raise_error(InvalidAccountNumberError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
You can see that within the Specify-provided `Feature` construct I have the standard `let` and `subject` elements. Within the Specify-provided `Scenario` you can see I use a Specify-provide method (`test`) and an RSpec-provided method (`it`).
|
77
|
+
|
78
|
+
Modern development practices put an emphasis on communication. Much of this communication is done via the mechanisms of tests. These tests ideally act as readable specifications that communicate the intent of a test. Equally ideally, however, these tests do not hide the code that executes them behind too many layers of abstractions.
|
79
|
+
|
80
|
+
Tools in the xSpec family, of which RSpec is a part, do a good job of keeping code as a first-class citizen. This is contrasted with tools in the xBehave family, of which Cucumber is a part, where you have various abstractions like feature files sitting in front of code. Beyond that you also often have an intermediary layer, like the step definition files of Cucumber, that add one more layer of maintenance.
|
81
|
+
|
82
|
+
Beyond even that, such xBehave tools often do limit you to the expressions available via a structuring syntax, such as with the Gherkin API, that is outside of the code.
|
83
|
+
|
84
|
+
Specify lets you write as much logic beside your specifications as you want by leveraging the RSpec ecosystem with the addition of a Gherkin-like syntax as well as additions to that syntax. Perhaps worth noting is that Specify has no dependence on Gherkin.
|
85
|
+
|
86
|
+
The [unit tests](https://github.com/jeffnyman/specify/tree/master/spec) will give you some idea of how Specify allows the structuring of test specifications.
|
87
|
+
|
88
|
+
### The Specify API
|
89
|
+
|
90
|
+
In RSpec, `describe` creates an example group and `it` creates a single example. You can use `context` as an alias for `describe` and you can use `example` and `specify` as aliases for `it`. Specify does a couple of things in the context of the API that RSpec provides.
|
91
|
+
|
92
|
+
Specify adds a few new example groups: `Feature` and `Story`. These are considered top-level example groups. Because they are top-level, they are mutually exlcusive so you can't have one nested within the other.
|
93
|
+
|
94
|
+
Specify also provides another set of example groups: `Ability`, `Component`, `Workflow`, and `Service`. These can be nested within one another and can be nested within the top-level example groups.
|
95
|
+
|
96
|
+
Specify provides some constructs that map to RSpec hooks as well: `Background` and `Setup` (both of which act like an RSpec `before`) along with `Teardown` and `Cleanup` (both of which act like an RSpec `after`).
|
97
|
+
|
98
|
+
As a very simple example, consider this:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Feature 'The Nature of Truth' do
|
102
|
+
Ability 'logic tests can be applied' do
|
103
|
+
Scenario 'true is not false' do
|
104
|
+
Then 'true is almost certainly not false' do
|
105
|
+
expect(true).to_not be false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Scenario 'true is true' do
|
110
|
+
Then 'true is pretty definitely true' do
|
111
|
+
expect(true).to be true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
Gherkin structures allow you to use the word "Ability" as an alias for "Feature". However Specify takes the viewpoint that a feature could be speaking to a high-level viewpoint, within which there are multiple abilities. Thus you can use both descriptors simultaneously, one nested within the other, which would not be possible with Gherkin. You can also see here that multiple Scenario blocks can be included within a Feature or Ability just as they would in Gherkin.
|
119
|
+
|
120
|
+
You might know that RSpec allows you to define your own names for its constructs already. For example, I could do something like this:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
RSpec.configure do |rspec|
|
124
|
+
rspec.alias_example_group_to :scenario
|
125
|
+
rspec.alias_example_to :then
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
So why wouldn't you just do that instead of using something like Specify? The answer lies in realizing that the `Scenario` implementation provided by Specify is not just acting as an alias for `context`. Rather, Specify hooks into RSpec to change the execution. This is done by extending RSpec to support step groups.
|
130
|
+
|
131
|
+
### Specify Augments RSpec
|
51
132
|
|
52
|
-
|
133
|
+
RSpec is predicated upon unit testing or, at most, integration testing. Thus RSpec focuses on providing a runner that works for edge-to-edge tests. As such, RSpec's mode of action is that all examples should be completely independent. Consider this:
|
53
134
|
|
54
|
-
|
135
|
+
```ruby
|
136
|
+
context 'Simple Scenario' do
|
137
|
+
it 'sets up some context' do
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'takes some action'
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'observes some result' do
|
144
|
+
end
|
145
|
+
end
|
146
|
+
```
|
55
147
|
|
56
|
-
|
148
|
+
Here each it block is a step but also is one independent test. The conditions for passing or failing must be within each step. Contrast this with a Cucumber feature scenario:
|
149
|
+
|
150
|
+
```
|
151
|
+
Scenario: 'Simple Scenario'
|
152
|
+
Given some context
|
153
|
+
When some action
|
154
|
+
Then some result
|
155
|
+
```
|
57
156
|
|
58
|
-
|
157
|
+
Here the `Scenario` block has three steps but they are not independent. They have to work together to be considered a passing or failing test.
|
59
158
|
|
60
|
-
|
159
|
+
So, for end-to-end purposes, this means if you want to use RSpec you have to write a sequence of examples, each of which repeats the behavior of all previous examples. Another alternative is that you could write one single large example that performs the entire set of actions. The problem in that case is that there is no independent reporting of each step. Or you could try to rely on a clever use of `before` and `after` calls. The problem there is that the `before` and `after` logic may differ significantly between tests. This is why tools like Cucumber end up being used.
|
61
160
|
|
62
|
-
|
161
|
+
So that's one of the goals of Specify: provide just the good parts of Cucumber and skip all the questionable parts.
|
162
|
+
|
163
|
+
At minimum this means the ability to chain examples into a series of steps that run in sequence and which stop when a step fails. This allows you to assemble a series of tests that should all pass, but where complete isolation of those tests is not sensible. Given how Specify augments RSpec, this allows RSpec to be less unit and more integration and certainly more end-to-end.
|
164
|
+
|
165
|
+
Key to this is the ability to share state between example steps.
|
166
|
+
|
167
|
+
To that end, within the idea of an example group, Specify provides some constructs that are marked with metadata of "has_steps": `Scenario`, `Behavior`, and `Condition`. You can use non-capitalized variations of these as well. These are considered step groups. These cannot be nested within one another.
|
168
|
+
|
169
|
+
You can also use the following: `Steps`, `Rules`, `Tests`, `Facts` (along with non-capitalized variants). These are just meant to accommodate various ways of expressing tests but they also show you how Specify can be used to provide a grammar that is as expressive as you would like it to be.
|
170
|
+
|
171
|
+
Specify allows the normal RSpec `it`, `example`, and `specify` example keywords to be used within these step groups. However, Specify also adds a few other example keywords based on the above constructs: `step`, `rule`, `test`, and `fact`. Specify also provides the Gherkin style keywords as examples: `Given`, `When`, `Then`, `And`, and `But`.
|
172
|
+
|
173
|
+
RSpec provides multiple ways to create and use shared example groups. These come in pairs, with one method for defining a shared group and another for using it. So, in RSpec, `shared_context` and `include_context` are for reusing common setup and helper logic whereas `shared_examples` and `include_examples` are for reusing examples. Specify hooks into this general mechanism and provides `shared_steps` and `include_steps`. These shared steps go into RSpec's "world," which is an internal container that is used for holding global non-configuration data.
|
174
|
+
|
175
|
+
## Development
|
176
|
+
|
177
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec:all` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
178
|
+
|
179
|
+
To experiment with the code, run `bin/console` for an interactive prompt. If you want to make changes and see how they work as a gem installed on your local machine, run `bundle exec rake install`.
|
180
|
+
|
181
|
+
The default `rake` command will run all tests as well as a Rubocop analysis.
|
182
|
+
|
183
|
+
If you have rights to deploy a new version, make sure to update the version number in `version.rb`, and then run `bundle exec rake release`. This will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
63
184
|
|
64
185
|
## Contributing
|
65
186
|
|
66
|
-
|
187
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/jeffnyman/specify](https://github.com/jeffnyman/specify). The testing ecosystem of Ruby is very large and this project is intended to be a welcoming arena for collaboration on yet another test-supporting tool. As such, contributors are very much welcome but are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) which is provided as a [code of conduct](https://github.com/jeffnyman/specify/blob/master/CODE_OF_CONDUCT.md).
|
188
|
+
|
189
|
+
The Specify gems follows [semantic versioning](http://semver.org).
|
190
|
+
|
191
|
+
To contribute to Specify:
|
67
192
|
|
68
193
|
1. [Fork the project](http://gun.io/blog/how-to-github-fork-branch-and-pull-request/).
|
69
|
-
2. Create
|
194
|
+
2. Create your feature branch. (`git checkout -b my-new-feature`)
|
70
195
|
3. Commit your changes. (`git commit -am 'new feature'`)
|
71
196
|
4. Push the branch. (`git push origin my-new-feature`)
|
72
197
|
5. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
|
@@ -78,13 +203,14 @@ To work on Specify:
|
|
78
203
|
## License
|
79
204
|
|
80
205
|
Specify is distributed under the [MIT](http://www.opensource.org/licenses/MIT) license.
|
81
|
-
See the [LICENSE](https://github.com/
|
206
|
+
See the [LICENSE](https://github.com/jeffnyman/specify/blob/master/LICENSE.md) file for details.
|
82
207
|
|
83
208
|
## Credits
|
84
209
|
|
85
|
-
Specify has been inspired by the following projects
|
210
|
+
Specify has been inspired by the following projects. Each provided me with ideas for what to do and, in some cases, for what not to do. All were invaluable as I better considered how to leverage RSpec's functionality.
|
86
211
|
|
87
212
|
* [maniok_bdd](https://github.com/21croissants/maniok_bdd)
|
88
213
|
* [rspec-gherkin](https://github.com/sheerun/rspec-gherkin)
|
89
214
|
* [rspec example steps](https://github.com/railsware/rspec-example_steps)
|
90
215
|
* [XSpec](https://github.com/xaviershay/xspec)
|
216
|
+
* [Mouse Melon](https://github.com/wojtha/mouse_melon)
|