specify 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6bd52074c94486ea349b2b8a64811cbe1407ffcc
4
- data.tar.gz: 4ca92a95cf2169533e5aed1abee1afd6fa4d01a6
3
+ metadata.gz: 0e886dff9cb121d9b139f79b7bbfbe0fbfb015d6
4
+ data.tar.gz: ba3900c1895de6e1e3c42d0709ce770fa708bdce
5
5
  SHA512:
6
- metadata.gz: c0ce369f131e8fbfcee0a790a9e803345935fa54cc0c0486a9f7ffb37ebb00c35c682c735ddd00067fc7610a0ab02d5ced9175792ef8dab4004de8e287f98aac
7
- data.tar.gz: 50bde5b576fb61613173952fc1b2bd90d868832b784354b71fa70e988243e88e6f39153ca45c0643fc205e0099667fd7c22d9cfb9df2802cb90854c97a3c41b8
6
+ metadata.gz: 11d8a7eacd4b0d70047d270d1153cab8700bca9a40419e7930ff9a49bf684af953d0bd7cf3bb3095cf1150189768d320c6a74043a09a4b533ef24f783f0725cd
7
+ data.tar.gz: dd1977da7b7b94864500fa533eb859c6cd731d5eac70a9609513273fd85f8f0c571bd367c19299e94deb5c0accb8aae0fa6eca3c7a20acbe459049d955e190eb
data/.gitignore CHANGED
@@ -13,3 +13,4 @@
13
13
  *.o
14
14
  *.a
15
15
  mkmf.log
16
+ .DS_Store
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Specify
2
2
 
3
- Specify parses test specifications written in Gherkin format and runs them via RSpec.
3
+ Specify is a BDD-style micro-framework.
4
4
 
5
- The goal of Specify is to separate the concepts behind tools like Cucumber and Lucid from their implementation. The latter has been weak in some cases but the former has been strong.
5
+ Specify is a very thin wrapper around RSpec that provides a Gherkin-style syntax for use with test examples.
6
6
 
7
7
  ## Installation
8
8
 
@@ -22,7 +22,119 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- Further details on usage will be coming as Specify evolves.
25
+ To use Specify you simply have to require it within your `spec_helper` file.
26
+
27
+ While Specify does provide a Gherkin-like syntax, there is no parsing of a Gherkin feature and step definition matching. Just as in RSpec, everything is in one place: the Ruby file. The benefit here is that you don't have to change the text in two places (feature file and step definition file) every time you change something. Further, there are no more matchers to sync up with natural language. Specify uses plain Ruby helper methods coupled with various patterns.
28
+
29
+ ### Integration Tests
30
+
31
+ RSpec's mode of action is that all examples should be completely independent. This is in line with its focus as primarily a unit-based testing framework. For integration 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.
32
+
33
+ This is why tools like Cucumber end up being used.
34
+
35
+ However the only benefit there is the ability to execute some examples in sequence and skip subsequent steps after a failure.
36
+
37
+ So that's the goal of Specify: provide just the good parts of Cucumber and skipping all the questionable parts. 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. The idea is to assemble a series of tests that should all pass, but where completely isolating them is not sensible. Hooking this into RSpec, this would make RSpec less unit and more integration.
38
+
39
+ ### Example
40
+
41
+ Consider this example of a standard RSpec example group:
42
+
43
+ ```ruby
44
+ describe 'Basic Spec Structure' do
45
+ context 'when simple logic tests are applied' do
46
+ it 'will agree that true almost certainly not false' do
47
+ expect(true).to_not be false
48
+ end
49
+
50
+ it 'will agree that true is pretty definitely true' do
51
+ expect(true).to be true
52
+ end
53
+ end
54
+ end
55
+
56
+ describe 'Simple Scenarios' do
57
+ context 'with an instance variable' do
58
+ it 'will establish a variable' do
59
+ @active = 'testing'
60
+ expect(@active).to eq 'testing'
61
+ end
62
+
63
+ it 'will reference the instance variable' do
64
+ puts "@active = #{@active}"
65
+ expect(@active).to eq 'testing'
66
+ end
67
+ end
68
+ end
69
+ ```
70
+
71
+ Now consider how this can work with Specify. You will have a "steps" block. Within that, all examples run in order of specification. State is preserved between examples within the "steps" block. If any example inside the "steps" block fails, all remaining steps will be marked as pending and thus skipped.
72
+
73
+ ```ruby
74
+ context 'when simple logic tests are applied' do
75
+ steps do
76
+ Given 'true is almost certainly not false' do
77
+ expect(true).to_not be false
78
+ end
79
+
80
+ Given 'true is pretty definitely true' do
81
+ expect(true).to be true
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'Simple Scenarios' do
87
+ steps 'with an instance variable' do
88
+ When 'it establishes an instance variable' do
89
+ @active = 'testing'
90
+ expect(@active).to eq 'testing'
91
+ end
92
+
93
+ Then 'that instance variable can be referenced' do
94
+ puts "@active = #{@active}"
95
+ expect(@active).to eq 'testing'
96
+ end
97
+ end
98
+ end
99
+ ```
100
+
101
+ ### Shared Steps
102
+
103
+ You can use `shared_steps` to define a block that will be evaluated in the context of an example. The example must use the `include_steps` directive. Here is an example of some shared steps:
104
+
105
+ ```ruby
106
+ shared_steps 'login' do |email, password|
107
+ When 'I go to login page' do
108
+ puts 'Go to the login page'
109
+ end
110
+
111
+ When 'I put credentials' do
112
+ puts "Email: #{email}, Password: #{password}"
113
+ end
114
+ end
115
+
116
+ shared_steps 'invalid login' do
117
+ Then 'I should see login error' do
118
+ puts 'Expect a login error'
119
+ end
120
+ end
121
+ ```
122
+
123
+ Here is how those steps can be used:
124
+
125
+ ```ruby
126
+ context 'action' do
127
+ steps 'User provides wrong email' do
128
+ include_steps 'login', 'jeff', 'invalid'
129
+ include_steps 'invalid login'
130
+ end
131
+
132
+ steps 'User provides wrong password' do
133
+ include_steps 'login', 'jeff@example.com', 'testing'
134
+ include_steps 'invalid login'
135
+ end
136
+ end
137
+ ```
26
138
 
27
139
  ## Contributing
28
140
 
@@ -33,3 +145,11 @@ To work on Specify:
33
145
  3. Commit your changes. (`git commit -am 'new feature'`)
34
146
  4. Push the branch. (`git push origin my-new-feature`)
35
147
  5. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
148
+
149
+ ## Authors
150
+
151
+ * [Jeff Nyman](http://testerstories.com)
152
+
153
+ ## License
154
+
155
+ Specify is distributed under the [MIT](http://www.opensource.org/licenses/MIT) license.
data/Rakefile CHANGED
@@ -1,3 +1,2 @@
1
- #!/usr/bin/env rake
2
1
  require 'bundler/gem_tasks'
3
2
 
@@ -0,0 +1,57 @@
1
+ module RSpec
2
+ module Specify
3
+ module DocumentationFormatter
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+
8
+ alias :example_started_without_steps :example_started
9
+ alias :example_started :example_started_with_steps
10
+
11
+ alias :example_passed_without_steps :example_passed
12
+ alias :example_passed :example_passed_with_steps
13
+ end
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+ def example_started(notification)
19
+ end
20
+
21
+ def example_step_passed(notification)
22
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
23
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :success)
24
+ end
25
+
26
+ def example_step_failed(notification)
27
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message} (FAILED)"
28
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :failure)
29
+ end
30
+
31
+ def example_step_pending(notification)
32
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
33
+
34
+ if notification.options[:pending] && notification.options[:pending] != true
35
+ full_message << " (PENDING: #{notification.options[:pending]})"
36
+ else
37
+ full_message << ' (PENDING)'
38
+ end
39
+
40
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :pending)
41
+ end
42
+
43
+ def example_started_with_steps(notification)
44
+ example_started_without_steps(notification)
45
+
46
+ if notification.example.metadata[:with_steps]
47
+ full_message = "#{current_indentation}#{notification.example.description}"
48
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :default)
49
+ end
50
+ end
51
+
52
+ def example_passed_with_steps(notification)
53
+ example_passed_without_steps(notification) unless notification.example.metadata[:with_steps]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,32 @@
1
+ module RSpec
2
+ module Specify
3
+ module ExampleGroup
4
+ def include_steps(*args)
5
+ name = args.shift
6
+ shared_block = RSpec.world.shared_example_steps[name]
7
+ shared_block or raise ArgumentError, "Could not find shared steps #{name.inspect}"
8
+ instance_exec(*args, &shared_block)
9
+ end
10
+
11
+ def Given(message, options={}, &block)
12
+ RSpec.world.reporter.process_example_step(self, :given, message, options, &block)
13
+ end
14
+
15
+ def When(message, options={}, &block)
16
+ RSpec.world.reporter.process_example_step(self, :when, message, options, &block)
17
+ end
18
+
19
+ def Then(message, options={}, &block)
20
+ RSpec.world.reporter.process_example_step(self, :then, message, options, &block)
21
+ end
22
+
23
+ def And(message, options = {}, &block)
24
+ RSpec.world.reporter.process_example_step(self, :and, message, options, &block)
25
+ end
26
+
27
+ def But(message, options = {}, &block)
28
+ RSpec.world.reporter.process_example_step(self, :but, message, options, &block)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ module RSpec
2
+ module Specify
3
+ class Notification < Struct.new(:example, :type, :message, :options)
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,45 @@
1
+ module RSpec
2
+ module Specify
3
+ module Reporter
4
+ def process_example_step(example, type, message, options)
5
+ example_step_started(self, type, message, options)
6
+
7
+ if block_given? && !options[:pending]
8
+ begin
9
+ yield
10
+ rescue Exception => e
11
+ example_step_failed(self, type, message, options)
12
+ raise e
13
+ end
14
+ example_step_passed(self, type, message, options)
15
+ else
16
+ example_step_pending(self, type, message, options)
17
+ end
18
+ end
19
+
20
+ def example_step_started(example, type, message, options)
21
+ notify :example_step_started, Notification.new(example, type, message, options)
22
+ end
23
+
24
+ def example_step_passed(example, type, message, options)
25
+ notify :example_step_passed, Notification.new(example, type, message, options)
26
+ end
27
+
28
+ def example_step_failed(example, type, message, options)
29
+ notify :example_step_failed, Notification.new(example, type, message, options)
30
+ end
31
+
32
+ def example_step_pending(example, type, message, options)
33
+ notify :example_step_pending, Notification.new(example, type, message, options)
34
+ end
35
+
36
+ def registered_formatters
37
+ @listeners.values.map(&:to_a).flatten.uniq
38
+ end
39
+
40
+ def find_registered_formatter(cls)
41
+ registered_formatters.detect { |formatter| formatter.class == cls }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module RSpec
2
+ module Specify
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
+ if RSpec.world.shared_example_steps.has_key?(name)
13
+ raise ArgumentError.new("Shared step '#{name}' already exists")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module RSpec
2
+ module Specify
3
+ module World
4
+ def shared_example_steps
5
+ @shared_example_steps ||= {}
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Specify
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/specify.rb CHANGED
@@ -2,3 +2,40 @@ require 'specify/version'
2
2
 
3
3
  module Specify
4
4
  end
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/example_group'
8
+ require 'rspec/core/reporter'
9
+ require 'rspec/core/world'
10
+ require 'rspec/core/formatters'
11
+ require 'rspec/core/formatters/console_codes'
12
+ require 'rspec/core/formatters/documentation_formatter'
13
+
14
+ require 'specify/rspec/example_group'
15
+ require 'specify/rspec/notification'
16
+ require 'specify/rspec/reporter'
17
+ require 'specify/rspec/world'
18
+ require 'specify/rspec/documentation_formatter'
19
+
20
+ RSpec::Core::ExampleGroup.send :include, RSpec::Specify::ExampleGroup
21
+ RSpec::Core::Reporter.send :include, RSpec::Specify::Reporter
22
+ RSpec::Core::World.send :include, RSpec::Specify::World
23
+
24
+ RSpec::Core::Formatters::DocumentationFormatter.send :include, RSpec::Specify::DocumentationFormatter
25
+
26
+ if formatter = RSpec.world.reporter.find_registered_formatter(RSpec::Core::Formatters::DocumentationFormatter)
27
+ RSpec.world.reporter.register_listener(
28
+ formatter,
29
+ :example_started,
30
+ :example_step_passed,
31
+ :example_step_pending,
32
+ :example_step_failed
33
+ )
34
+ end
35
+
36
+
37
+ RSpec::Core::ExampleGroup.define_example_method :steps, with_steps: true
38
+ RSpec::Core::ExampleGroup.define_example_method :Scenario, with_steps: true
39
+
40
+ require 'specify/rspec/shared_steps'
41
+ include RSpec::Specify::SharedSteps
data/specify.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.files = `git ls-files -z`.split("\x0")
22
22
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
23
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
- spec.require_paths = %w(lib)
24
+ spec.require_paths = ['lib']
25
25
 
26
26
  spec.required_ruby_version = '>= 2.0.0'
27
27
  spec.required_rubygems_version = '>= 1.8.29'
@@ -29,8 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'bundler', '~> 1.7'
30
30
  spec.add_development_dependency 'rake', '~> 10.0'
31
31
 
32
- spec.add_runtime_dependency 'gherkin', '~> 2.12'
33
- spec.add_runtime_dependency 'rspec', '~> 3.0'
32
+ spec.add_runtime_dependency 'rspec-core', '~> 3.0'
34
33
 
35
34
  spec.post_install_message = %{
36
35
  (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Nyman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-04 00:00:00.000000000 Z
11
+ date: 2014-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,21 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: gherkin
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.12'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.12'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
42
+ name: rspec-core
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
@@ -82,6 +68,12 @@ files:
82
68
  - README.md
83
69
  - Rakefile
84
70
  - lib/specify.rb
71
+ - lib/specify/rspec/documentation_formatter.rb
72
+ - lib/specify/rspec/example_group.rb
73
+ - lib/specify/rspec/notification.rb
74
+ - lib/specify/rspec/reporter.rb
75
+ - lib/specify/rspec/shared_steps.rb
76
+ - lib/specify/rspec/world.rb
85
77
  - lib/specify/version.rb
86
78
  - specify.gemspec
87
79
  homepage: https://github.com/jnyman/specify
@@ -89,7 +81,7 @@ licenses:
89
81
  - MIT
90
82
  metadata: {}
91
83
  post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n\n
92
- \ Specify 0.0.1 has been installed.\n\n(::) (::) (::) (::) (::) (::) (::) (::) (::)
84
+ \ Specify 0.1.0 has been installed.\n\n(::) (::) (::) (::) (::) (::) (::) (::) (::)
93
85
  (::) (::) (::)\n "
94
86
  rdoc_options: []
95
87
  require_paths: