test_spec 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +46 -0
- data/.hound.yml +69 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/LICENSE.md +21 -0
- data/README.md +227 -0
- data/Rakefile +35 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/lib/test_spec.rb +38 -0
- data/lib/test_spec/rspec/example_group.rb +101 -0
- data/lib/test_spec/rspec/formatter.rb +53 -0
- data/lib/test_spec/rspec/notification.rb +12 -0
- data/lib/test_spec/rspec/reporter.rb +35 -0
- data/lib/test_spec/rspec/shared_steps.rb +18 -0
- data/lib/test_spec/rspec/world.rb +11 -0
- data/lib/test_spec/spec.rb +41 -0
- data/lib/test_spec/version.rb +3 -0
- data/test_spec.gemspec +38 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9de1b9a5b2ae221963420313565d64da5e982138
|
4
|
+
data.tar.gz: c3164a1dc1fedb62934d63a811beca414403bf1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 18702682dfd0d5ac8e69b35d7ebf65fdf86095fee1a1f80ce12608e119df6a01649745ed93fea92266365ffd92c99d71e039ab01d2eb548c9bfd3e23b63d0a33
|
7
|
+
data.tar.gz: f569b3d2d807ccd70f3fab61c486bb9dafab14674c2cedb275a9a7579f11e23001dee93f61a29a2864f7e09df5ce6529de4ad4d3854495ffcfa9ac6826b41514
|
data/.gitignore
ADDED
@@ -0,0 +1,46 @@
|
|
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
|
+
# Rspec Failure Tracking
|
15
|
+
|
16
|
+
.rspec_status
|
17
|
+
|
18
|
+
# IDE Files
|
19
|
+
|
20
|
+
.idea/
|
21
|
+
*.iml
|
22
|
+
*.iws
|
23
|
+
*.ipr
|
24
|
+
.vscode/
|
25
|
+
.settings/
|
26
|
+
.metadata
|
27
|
+
.classpath
|
28
|
+
.loadpath
|
29
|
+
.buildpath
|
30
|
+
.project
|
31
|
+
|
32
|
+
# OS Files
|
33
|
+
|
34
|
+
.DS_Store
|
35
|
+
.DS_Store?
|
36
|
+
._*
|
37
|
+
.Spotlight-V100
|
38
|
+
.Trashes
|
39
|
+
ehthumbs.db
|
40
|
+
Thumbs.db
|
41
|
+
$RECYCLE.BIN/
|
42
|
+
Desktop.ini
|
43
|
+
*.tmp
|
44
|
+
*.bak
|
45
|
+
*.swp
|
46
|
+
*~.nib
|
data/.hound.yml
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- test_spec.gemspec
|
4
|
+
- spec/**/*
|
5
|
+
|
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.
|
15
|
+
Style/Documentation:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
# Prefer reduce over inject.
|
19
|
+
Style/CollectionMethods:
|
20
|
+
PreferredMethods:
|
21
|
+
reduce: 'inject'
|
22
|
+
|
23
|
+
# Use each_with_object instead of inject.
|
24
|
+
Style/EachWithObject:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
# Prefer fail over raise.
|
28
|
+
Style/SignalException:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
# This never works for validations.
|
32
|
+
Layout/AlignHash:
|
33
|
+
EnforcedLastArgumentHashStyle: ignore_implicit
|
34
|
+
|
35
|
+
# Align multi-line params with previous line.
|
36
|
+
Layout/AlignParameters:
|
37
|
+
EnforcedStyle: with_fixed_indentation
|
38
|
+
|
39
|
+
# Indent `when` clause one step from `case`.
|
40
|
+
Layout/CaseIndentation:
|
41
|
+
IndentOneStep: true
|
42
|
+
|
43
|
+
# Don't force bad var names for reduce/inject loops.
|
44
|
+
Style/SingleLineBlockParams:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
# For method chains, keep the dot with the method name.
|
48
|
+
Layout/DotPosition:
|
49
|
+
EnforcedStyle: leading
|
50
|
+
|
51
|
+
# Stop nesting so hard.
|
52
|
+
Metrics/BlockNesting:
|
53
|
+
Max: 2
|
54
|
+
|
55
|
+
# Encourage short methods.
|
56
|
+
Metrics/MethodLength:
|
57
|
+
Max: 15
|
58
|
+
|
59
|
+
# Encourage short (as possible) modules.
|
60
|
+
Metrics/ModuleLength:
|
61
|
+
Max: 100
|
62
|
+
|
63
|
+
# Encourage fewer parameters.
|
64
|
+
Metrics/ParameterLists:
|
65
|
+
Max: 4
|
66
|
+
|
67
|
+
# Remove execute permissions check.
|
68
|
+
Lint/ScriptPermission:
|
69
|
+
Enabled: false
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
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.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
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
|
22
|
+
|
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
ADDED
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
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
# TestSpec
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/test_spec)
|
4
|
+
[](https://github.com/jeffnyman/test_spec/blob/master/LICENSE.md)
|
5
|
+
|
6
|
+
> **The height of sophistication is simplicity.**<br>
|
7
|
+
> *Clare Boothe Brokaw*
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
TestSpec is a tool for leveraging RSpec to create an expressive DSL for test and data conditions.
|
12
|
+
|
13
|
+
TestSpec 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).
|
14
|
+
|
15
|
+
Behavior Driven Development, or even just good Test Driven Development, practices put emphasis on communication. Tools like Cucumber focus on allowing communication via a test description language, structured by Gherkin keywords. However, while the ideas of Gherkin are nice, tools like Cucumber abstract away the nuts and bolts of your tests.
|
16
|
+
|
17
|
+
Abstraction can be a good thing but Cucumber gives you no choice in the matter. It hides code blocks behind a "call by regular expression" invocation mechanism instead of making those code blocks readily available in the test description.
|
18
|
+
|
19
|
+
TestSpec 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.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'test_spec'
|
27
|
+
```
|
28
|
+
|
29
|
+
To get the latest code:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
gem 'test_spec', git: 'https://github.com/jeffnyman/test_spec'
|
33
|
+
```
|
34
|
+
|
35
|
+
After doing one of the above, execute the following command:
|
36
|
+
|
37
|
+
```
|
38
|
+
$ bundle
|
39
|
+
```
|
40
|
+
|
41
|
+
You can also install TestSpec just as you would any other gem:
|
42
|
+
|
43
|
+
```
|
44
|
+
$ gem install test_spec
|
45
|
+
```
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
To use TestSpec you simply have to require it within your `spec_helper` file:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require 'test_spec'
|
53
|
+
```
|
54
|
+
|
55
|
+
Then you simply run your `rspec` command as normal against your test suite.
|
56
|
+
|
57
|
+
Because TestSpec uses a custom formatter, you should have an `.rspec` file with the following line in it:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
--format RSpec::TestSpec::Formatter
|
61
|
+
```
|
62
|
+
|
63
|
+
You can use RSpec constructs within Specify constructs although there are some things to be aware of. Here is an example:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
Feature 'Bank Accounts' do
|
67
|
+
let(:valid_account_number) { '1234567890' }
|
68
|
+
subject { Account.new(valid_account_number) }
|
69
|
+
|
70
|
+
Scenario 'starting a new account' do
|
71
|
+
Test 'will have a starting balance of 0' do
|
72
|
+
expect(subject.balance).to eq(0)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'will not allow an invalid account name' do
|
76
|
+
expect { Account.new('thx1138') }.to raise_error(InvalidAccountNumberError)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
You can see that within the Feature construct I have let and subject elements. Within the Scenario you can see I use a Specify method (Test) and an RSpec method (it).
|
83
|
+
|
84
|
+
## Documentation
|
85
|
+
|
86
|
+
TestSpec provides an internal DSL that allows you to use a Gherkin-like structural syntax within traditional RSpec test suites.
|
87
|
+
|
88
|
+
Note that while TestSpec does provide a Gherkin-like syntax, there is no parsing of an actual Gherkin feature file. This means there are no regular expression matchers that exist as part of step definitions.
|
89
|
+
|
90
|
+
Here's a typical (if simplified) example of a traditional RSpec test:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
describe 'The Nature of Truth' do
|
94
|
+
context 'logic tests are applied' do
|
95
|
+
it 'will realize that true is almost certainly not false' do
|
96
|
+
expect(true).to_not be false
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'will realize that true is pretty definitely true' do
|
100
|
+
expect(true).to be true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
The following examples will show how the above example can be utilized in the context of TestSpec's DSL.
|
107
|
+
|
108
|
+
As with Gherkin, you can provide a high-level **Feature** keyword to describe the overall set of tests. Here is one example of what you can do:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
Feature 'The Nature of Truth' do
|
112
|
+
tests 'logic tests are applied' do
|
113
|
+
test 'true is almost certainly not false' do
|
114
|
+
expect(true).to_not be false
|
115
|
+
end
|
116
|
+
|
117
|
+
test 'true is pretty definitely true' do
|
118
|
+
expect(true).to be true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
Notice here the **tests** keyword. This is an alias for elements like RSpec's `context`. Further notice that a **Test** keyword can be used. Some people think of tests in terms of steps and TestSpec can accommodate that as follows:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
Feature 'The Nature of Truth' do
|
128
|
+
steps 'logic tests are applied' do
|
129
|
+
step 'true is almost certainly not false' do
|
130
|
+
expect(true).to_not be false
|
131
|
+
end
|
132
|
+
|
133
|
+
step 'true is pretty definitely true' do
|
134
|
+
expect(true).to be true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
This is similar to the previous example, with the changes being the use of the **steps** and **Step** keywords.
|
141
|
+
|
142
|
+
Do note that unlike Gherkin feature files, you can have multiple **Feature** blocks within the test file. So you could have both of the above blocks co-existing and running together.
|
143
|
+
|
144
|
+
If you want to adhere even more strictly to Gherkin syntax, TestSpec does allow that:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
Feature 'The Nature of Truth' do
|
148
|
+
Scenario 'simple logic tests are applied' do
|
149
|
+
Then 'true is almost certainly not false' do
|
150
|
+
expect(true).to_not be false
|
151
|
+
end
|
152
|
+
|
153
|
+
Then 'true is pretty definitely true' do
|
154
|
+
expect(true).to be true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
Here you can see the use of the **Scenario** keyword, which is encapsulating two Then test steps.
|
161
|
+
|
162
|
+
Gherkin structures allow you to use the word "Ability" as an alias for "Feature". However TestSpec 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:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
Feature 'The Nature of Truth' do
|
166
|
+
Ability 'logic tests can be applied' do
|
167
|
+
Scenario 'true is not false' do
|
168
|
+
Then 'true is almost certainly not false' do
|
169
|
+
expect(true).to_not be false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Scenario 'true is true' do
|
174
|
+
Then 'true is pretty definitely true' do
|
175
|
+
expect(true).to be true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
You can also see here that multiple **Scenario** blocks can be included within a Feature or Ability.
|
183
|
+
|
184
|
+
This should give a rough idea of how TestSpec provides an internal DSL.
|
185
|
+
|
186
|
+
## Development
|
187
|
+
|
188
|
+
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.
|
189
|
+
|
190
|
+
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`.
|
191
|
+
|
192
|
+
The default `rake` command will run all tests as well as a Rubocop analysis.
|
193
|
+
|
194
|
+
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).
|
195
|
+
|
196
|
+
## Contributing
|
197
|
+
|
198
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/jeffnyman/test_spec](https://github.com/jeffnyman/test_spec). 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/test_spec/blob/master/CODE_OF_CONDUCT.md).
|
199
|
+
|
200
|
+
The TestSpec gems follows [semantic versioning](http://semver.org).
|
201
|
+
|
202
|
+
To contribute to TestSpec:
|
203
|
+
|
204
|
+
1. [Fork the project](http://gun.io/blog/how-to-github-fork-branch-and-pull-request/).
|
205
|
+
2. Create your feature branch. (`git checkout -b my-new-feature`)
|
206
|
+
3. Commit your changes. (`git commit -am 'new feature'`)
|
207
|
+
4. Push the branch. (`git push origin my-new-feature`)
|
208
|
+
5. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
|
209
|
+
|
210
|
+
## Author
|
211
|
+
|
212
|
+
* [Jeff Nyman](http://testerstories.com)
|
213
|
+
|
214
|
+
## License
|
215
|
+
|
216
|
+
TestSpec is distributed under the [MIT](http://www.opensource.org/licenses/MIT) license.
|
217
|
+
See the [LICENSE](https://github.com/jeffnyman/test_spec/blob/master/LICENSE.md) file for details.
|
218
|
+
|
219
|
+
## Credits
|
220
|
+
|
221
|
+
TestSpec 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.
|
222
|
+
|
223
|
+
* [maniok_bdd](https://github.com/21croissants/maniok_bdd)
|
224
|
+
* [rspec-gherkin](https://github.com/sheerun/rspec-gherkin)
|
225
|
+
* [rspec example steps](https://github.com/railsware/rspec-example_steps)
|
226
|
+
* [XSpec](https://github.com/xaviershay/xspec)
|
227
|
+
* [Mouse Melon](https://github.com/wojtha/mouse_melon)
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require "rdoc/task"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
require "rspec/core/rake_task"
|
7
|
+
|
8
|
+
RuboCop::RakeTask.new
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
|
12
|
+
namespace :spec do
|
13
|
+
desc 'Clean all generated reports'
|
14
|
+
task :clean do
|
15
|
+
system('rm -rf spec/reports')
|
16
|
+
system('rm -rf spec/coverage')
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::RakeTask.new(all: :clean) do |config|
|
20
|
+
options = %w[--color]
|
21
|
+
options += %w[--format documentation]
|
22
|
+
options += %w[--format html --out spec/reports/unit-test-report.html]
|
23
|
+
|
24
|
+
config.rspec_opts = options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Rake::RDocTask.new do |rdoc|
|
29
|
+
rdoc.rdoc_dir = 'doc'
|
30
|
+
rdoc.main = 'README.md'
|
31
|
+
rdoc.title = "TestSpec #{TestSpec::VERSION}"
|
32
|
+
rdoc.rdoc_files.include('README*', 'lib/**/*.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
task default: ['spec:all', :rubocop]
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/test_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "rspec/core"
|
2
|
+
require "rspec/core/world"
|
3
|
+
require "rspec/core/reporter"
|
4
|
+
require "rspec/core/formatters"
|
5
|
+
require "rspec/core/example_group"
|
6
|
+
require "rspec/core/formatters/console_codes"
|
7
|
+
require "rspec/core/formatters/documentation_formatter"
|
8
|
+
|
9
|
+
require "test_spec/spec"
|
10
|
+
require "test_spec/version"
|
11
|
+
require "test_spec/rspec/world"
|
12
|
+
require "test_spec/rspec/reporter"
|
13
|
+
require "test_spec/rspec/formatter"
|
14
|
+
require "test_spec/rspec/notification"
|
15
|
+
require "test_spec/rspec/example_group"
|
16
|
+
|
17
|
+
RSpec::Core::ExampleGroup.send :include, RSpec::TestSpec::ExampleGroup
|
18
|
+
RSpec::Core::Reporter.send :include, RSpec::TestSpec::Reporter
|
19
|
+
RSpec::Core::World.send :include, RSpec::TestSpec::World
|
20
|
+
|
21
|
+
RSpec::Core::ExampleGroup.define_example_method :Scenario, with_steps: true
|
22
|
+
RSpec::Core::ExampleGroup.define_example_method :Condition, with_steps: true
|
23
|
+
RSpec::Core::ExampleGroup.define_example_method :Behavior, with_steps: true
|
24
|
+
|
25
|
+
RSpec::Core::ExampleGroup.define_example_method :Step, with_steps: true
|
26
|
+
RSpec::Core::ExampleGroup.define_example_method :Test, with_steps: true
|
27
|
+
RSpec::Core::ExampleGroup.define_example_method :Rule, with_steps: true
|
28
|
+
RSpec::Core::ExampleGroup.define_example_method :Fact, with_steps: true
|
29
|
+
|
30
|
+
RSpec::Core::ExampleGroup.define_example_method :steps, with_steps: true
|
31
|
+
RSpec::Core::ExampleGroup.define_example_method :rules, with_steps: true
|
32
|
+
RSpec::Core::ExampleGroup.define_example_method :tests, with_steps: true
|
33
|
+
RSpec::Core::ExampleGroup.define_example_method :facts, with_steps: true
|
34
|
+
|
35
|
+
require "test_spec/rspec/shared_steps"
|
36
|
+
# rubocop:disable Style/MixinUsage
|
37
|
+
include RSpec::TestSpec::SharedSteps
|
38
|
+
# rubocop:enable Style/MixinUsage
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module RSpec
|
2
|
+
module TestSpec
|
3
|
+
module ExampleGroup
|
4
|
+
# In Rspec, example group bodies are delimited by 'describe' and
|
5
|
+
# 'context' methods. These encapsulate examples, which are delimited
|
6
|
+
# by 'it' methods. Example groups are evaluated in the context of an
|
7
|
+
# ExampleGroup instance. Individual examples are evaluated in the
|
8
|
+
# context of an instance of the ExampleGroup to which they belong.
|
9
|
+
def include_steps(*args)
|
10
|
+
name = args.shift
|
11
|
+
|
12
|
+
shared_block = ::RSpec.world.shared_example_steps[name]
|
13
|
+
shared_block || raise(ArgumentError,
|
14
|
+
"Could not find shared steps #{name.inspect}")
|
15
|
+
|
16
|
+
instance_exec(*args, &shared_block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# rubocop:disable Naming/MethodName
|
20
|
+
def Given(message, options = {}, &block)
|
21
|
+
action :given, message, options, &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def When(message, options = {}, &block)
|
25
|
+
action :when, message, options, &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def Then(message, options = {}, &block)
|
29
|
+
action :then, message, options, &block
|
30
|
+
end
|
31
|
+
|
32
|
+
def And(message, options = {}, &block)
|
33
|
+
action :and, message, options, &block
|
34
|
+
end
|
35
|
+
|
36
|
+
def But(message, options = {}, &block)
|
37
|
+
action :but, message, options, &block
|
38
|
+
end
|
39
|
+
# rubocop:enable Naming/MethodName
|
40
|
+
|
41
|
+
def rule(message, options = {}, &block)
|
42
|
+
action :rule, message, options, &block
|
43
|
+
end
|
44
|
+
|
45
|
+
def fact(message, options = {}, &block)
|
46
|
+
action :fact, message, options, &block
|
47
|
+
end
|
48
|
+
|
49
|
+
def test(message, options = {}, &block)
|
50
|
+
action :test, message, options, &block
|
51
|
+
end
|
52
|
+
|
53
|
+
def step(message, options = {}, &block)
|
54
|
+
action :step, message, options, &block
|
55
|
+
end
|
56
|
+
|
57
|
+
def it(message, options = {}, &block)
|
58
|
+
action :it, message, options, &block
|
59
|
+
end
|
60
|
+
|
61
|
+
def specify(message, options = {}, &block)
|
62
|
+
action :specify, message, options, &block
|
63
|
+
end
|
64
|
+
|
65
|
+
def example(message, options = {}, &block)
|
66
|
+
action :example, message, options, &block
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# rubocop:disable Metrics/AbcSize
|
72
|
+
# rubocop:disable Metrics/MethodLength
|
73
|
+
def action(type, message, options = {}, &_block)
|
74
|
+
::RSpec.world.reporter.example_step_started(
|
75
|
+
self, type, message, options
|
76
|
+
)
|
77
|
+
options = { pending: true } if options == :pending
|
78
|
+
|
79
|
+
if block_given? && !options[:pending]
|
80
|
+
begin
|
81
|
+
yield
|
82
|
+
rescue StandardError => e
|
83
|
+
::RSpec.world.reporter.example_step_failed(
|
84
|
+
self, type, message, options
|
85
|
+
)
|
86
|
+
raise e
|
87
|
+
end
|
88
|
+
::RSpec.world.reporter.example_step_passed(
|
89
|
+
self, type, message, options
|
90
|
+
)
|
91
|
+
else
|
92
|
+
::RSpec.world.reporter.example_step_pending(
|
93
|
+
self, type, message, options
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
# rubocop:enable Metrics/AbcSize
|
98
|
+
# rubocop:enable Metrics/MethodLength
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "rspec/core/formatters/documentation_formatter"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module TestSpec
|
5
|
+
class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
|
6
|
+
::RSpec::Core::Formatters.register(
|
7
|
+
self,
|
8
|
+
:example_started, :example_passed, :example_step_passed,
|
9
|
+
:example_step_pending, :example_step_failed
|
10
|
+
)
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/LineLength
|
13
|
+
def example_started(notification)
|
14
|
+
return unless notification.example.metadata[:with_steps]
|
15
|
+
|
16
|
+
full_message = "#{current_indentation}#{notification.example.description}"
|
17
|
+
output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :default)
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_passed(notification)
|
21
|
+
super unless notification.example.metadata[:with_steps]
|
22
|
+
end
|
23
|
+
|
24
|
+
def example_step_passed(notification)
|
25
|
+
full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
|
26
|
+
output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :success)
|
27
|
+
end
|
28
|
+
|
29
|
+
# rubocop:disable Metrics/AbcSize
|
30
|
+
# rubocop:disable Style/ConditionalAssignment
|
31
|
+
def example_step_pending(notification)
|
32
|
+
full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
|
33
|
+
|
34
|
+
if notification.options[:pending] &&
|
35
|
+
notification.options[:pending] != true
|
36
|
+
full_message << " (PENDING: #{notification.options[:pending]})"
|
37
|
+
else
|
38
|
+
full_message << " (PENDING)"
|
39
|
+
end
|
40
|
+
|
41
|
+
output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :pending)
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/AbcSize
|
44
|
+
# rubocop:enable Style/ConditionalAssignment
|
45
|
+
|
46
|
+
def example_step_failed(notification)
|
47
|
+
full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message} (FAILED)"
|
48
|
+
output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :failure)
|
49
|
+
end
|
50
|
+
# rubocop:enable Metrics/LineLength
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module RSpec
|
2
|
+
module TestSpec
|
3
|
+
# In RSpec, notifications are value objects that are passed to formatters
|
4
|
+
# to provide those formatters with information about a particular event.
|
5
|
+
|
6
|
+
Notification = Struct.new(:example, :type, :message, :options)
|
7
|
+
|
8
|
+
# Originally I did this:
|
9
|
+
# class Notification < Struct.new(:example, :type, :message, :options)
|
10
|
+
# end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RSpec
|
2
|
+
module TestSpec
|
3
|
+
module Reporter
|
4
|
+
# An RSpec reporter sends notifications to listeners. The listeners
|
5
|
+
# are usually formatters for a specific test run.
|
6
|
+
def example_step_started(example, type, message, options)
|
7
|
+
notify :example_step_started,
|
8
|
+
Notification.new(example, type, message, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def example_step_passed(example, type, message, options)
|
12
|
+
notify :example_step_passed,
|
13
|
+
Notification.new(example, type, message, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def example_step_failed(example, type, message, options)
|
17
|
+
notify :example_step_failed,
|
18
|
+
Notification.new(example, type, message, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def example_step_pending(example, type, message, options)
|
22
|
+
notify :example_step_pending,
|
23
|
+
Notification.new(example, type, message, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def registered_formatters
|
27
|
+
@listeners.values.map(&:to_a).flatten.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_registered_formatter(cls)
|
31
|
+
registered_formatters.detect { |formatter| formatter.class == cls }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RSpec
|
2
|
+
module TestSpec
|
3
|
+
module SharedSteps
|
4
|
+
def shared_steps(name, &block)
|
5
|
+
ensure_shared_example_steps_name_not_taken(name)
|
6
|
+
::RSpec.world.shared_example_steps[name] = block
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def ensure_shared_example_steps_name_not_taken(name)
|
12
|
+
return unless ::RSpec.world.shared_example_steps.key?(name)
|
13
|
+
|
14
|
+
raise(ArgumentError, "Shared step '#{name}' already exists")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TestSpec
|
2
|
+
module Spec
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_eval do
|
5
|
+
alias :Feature :context
|
6
|
+
alias :Ability :context
|
7
|
+
alias :Story :context
|
8
|
+
alias :Component :context
|
9
|
+
alias :Workflow :context
|
10
|
+
|
11
|
+
alias :Background :before
|
12
|
+
alias :Setup :before
|
13
|
+
alias :Teardown :after
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# rubocop:disable Naming/MethodName
|
20
|
+
def self.Feature(*args, &block)
|
21
|
+
RSpec.describe(*args, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.Ability(*args, &block)
|
25
|
+
RSpec.describe(*args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.Story(*args, &block)
|
29
|
+
RSpec.describe(*args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.Component(*args, &block)
|
33
|
+
RSpec.describe(*args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.Workflow(*args, &block)
|
37
|
+
RSpec.describe(*args, &block)
|
38
|
+
end
|
39
|
+
# rubocop:enable Naming/MethodName
|
40
|
+
|
41
|
+
RSpec.configuration.include TestSpec::Spec
|
data/test_spec.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "test_spec/version"
|
5
|
+
require "date"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "test_spec"
|
9
|
+
spec.version = TestSpec::VERSION
|
10
|
+
spec.date = Date.today.strftime("%Y-%m-%d")
|
11
|
+
spec.authors = ["Jeff Nyman"]
|
12
|
+
spec.email = ["jeffnyman@gmail.com"]
|
13
|
+
|
14
|
+
spec.summary = %q{Test and Data Condition DSL for RSpec}
|
15
|
+
spec.description = %q{Test and Data Condition DSL for RSpec}
|
16
|
+
spec.homepage = "https://github.com/jeffnyman/test_spec"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
spec.add_development_dependency "simplecov"
|
30
|
+
spec.add_development_dependency "rubocop"
|
31
|
+
spec.add_development_dependency "pry"
|
32
|
+
|
33
|
+
spec.post_install_message = %{
|
34
|
+
(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
|
35
|
+
TestSpec #{TestSpec::VERSION} has been installed.
|
36
|
+
(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
|
37
|
+
}
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: test_spec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Nyman
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.17'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Test and Data Condition DSL for RSpec
|
98
|
+
email:
|
99
|
+
- jeffnyman@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".hound.yml"
|
106
|
+
- ".rspec"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- CODE_OF_CONDUCT.md
|
109
|
+
- Gemfile
|
110
|
+
- LICENSE.md
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/console
|
114
|
+
- bin/setup
|
115
|
+
- lib/test_spec.rb
|
116
|
+
- lib/test_spec/rspec/example_group.rb
|
117
|
+
- lib/test_spec/rspec/formatter.rb
|
118
|
+
- lib/test_spec/rspec/notification.rb
|
119
|
+
- lib/test_spec/rspec/reporter.rb
|
120
|
+
- lib/test_spec/rspec/shared_steps.rb
|
121
|
+
- lib/test_spec/rspec/world.rb
|
122
|
+
- lib/test_spec/spec.rb
|
123
|
+
- lib/test_spec/version.rb
|
124
|
+
- test_spec.gemspec
|
125
|
+
homepage: https://github.com/jeffnyman/test_spec
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
metadata: {}
|
129
|
+
post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n
|
130
|
+
\ TestSpec 0.1.0 has been installed.\n(::) (::) (::) (::) (::) (::) (::) (::) (::)
|
131
|
+
(::) (::) (::)\n "
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.5.2.2
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Test and Data Condition DSL for RSpec
|
151
|
+
test_files: []
|