spectie 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.rdoc +85 -0
- data/Rakefile +8 -0
- data/VERSION.yml +4 -0
- data/initialize.rb +6 -0
- data/lib/spectie.rb +3 -0
- data/lib/spectie/configuration.rb +10 -0
- data/lib/spectie/main.rb +26 -0
- data/lib/spectie/rails.rb +2 -0
- data/lib/spectie/rails_story_example_group.rb +55 -0
- data/lib/spectie/selenium.rb +3 -0
- data/lib/spectie/selenium/configuration.rb +27 -0
- data/lib/spectie/selenium/story_example_group.rb +51 -0
- data/lib/spectie/story_example_group_methods.rb +40 -0
- data/rake_tasks/package.rake +51 -0
- data/rake_tasks/publish.rake +40 -0
- data/rake_tasks/spec.rake +42 -0
- data/rake_tasks/utility.rake +11 -0
- data/rdoc/classes/Spectie.html +135 -0
- data/rdoc/classes/Spectie/Configuration.html +175 -0
- data/rdoc/classes/Spectie/Configuration/ForScenarios.html +111 -0
- data/rdoc/classes/Spectie/Configuration/Selenium.html +220 -0
- data/rdoc/classes/Spectie/Main.html +161 -0
- data/rdoc/classes/Spectie/RailsStoryExampleGroup.html +118 -0
- data/rdoc/classes/Spectie/SeleniumStoryExampleGroup.html +119 -0
- data/rdoc/classes/Spectie/StoryExampleGroupMethods.html +254 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/README_rdoc.html +266 -0
- data/rdoc/files/lib/spectie/configuration_rb.html +101 -0
- data/rdoc/files/lib/spectie/main_rb.html +108 -0
- data/rdoc/files/lib/spectie/rails_rb.html +109 -0
- data/rdoc/files/lib/spectie/rails_story_example_group_rb.html +182 -0
- data/rdoc/files/lib/spectie/selenium/configuration_rb.html +101 -0
- data/rdoc/files/lib/spectie/selenium/story_example_group_rb.html +101 -0
- data/rdoc/files/lib/spectie/selenium_rb.html +110 -0
- data/rdoc/files/lib/spectie/story_example_group_methods_rb.html +101 -0
- data/rdoc/files/lib/spectie_rb.html +110 -0
- data/rdoc/fr_class_index.html +34 -0
- data/rdoc/fr_file_index.html +36 -0
- data/rdoc/fr_method_index.html +38 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/script/selenium_webapp +45 -0
- data/script/spec +10 -0
- data/spec/example_run_state_tracking.rb +65 -0
- data/spec/selenium_config.rb +11 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/spectie/rails_helper.rb +29 -0
- data/spec/spectie/rails_story_example_group_spec.rb +59 -0
- data/spec/spectie/selenium/configuration_spec.rb +91 -0
- data/spec/spectie/selenium/spec_helper.rb +16 -0
- data/spec/spectie/selenium/story_example_group_spec.rb +132 -0
- data/spec/spectie/spec_helper.rb +1 -0
- data/spec/spectie/story_example_group_methods_spec.rb +217 -0
- data/spec/spectie_spec.rb +46 -0
- data/spec/support/rails_app/controllers/application_controller.rb +2 -0
- data/tags +19899 -0
- metadata +125 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Ryan Kinderman
|
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.rdoc
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
= Spectie
|
2
|
+
|
3
|
+
Spectie (rhymes with "necktie") is a pure Ruby BDD integration testing framework for RSpec.
|
4
|
+
|
5
|
+
Spectie was written with the following beliefs:
|
6
|
+
|
7
|
+
* Business stakeholders or analysts are often not writing comprehensive (or any) acceptance criteria.
|
8
|
+
* Business stakeholders or analysts are usually unwilling or unable to follow a strict format for writing the acceptance criteria that they _are_ writing.
|
9
|
+
* On many projects, the communication with the business stakeholders or analysts are accessible enough that written acceptance criteria is not necessary, but discussed requirements still need to be implemented, and therefore need to be tested.
|
10
|
+
* Good developers recognize the benefits of top-down, BDD-style integration testing in helping to ensure that the code that is written to implement a feature directly satisfies business requirements, and doesn't get over-engineered or over-complicated.
|
11
|
+
* Good developers love Ruby.
|
12
|
+
|
13
|
+
Spectie tries to strike the proper balance between writing readable tests, and just getting your work done in the most efficient way possible. It does this by providing a consistent structure for writing your integration test code in a BDD fashion, with the breakdown of features, scenarios, and their given/when/then statements. However, a little bit of syntactic sugar goes a long way to aid in the understanding of code, while too much can add unnecessary complexity and actually decrease maintainability. So, Spectie keeps things pretty close to the underlying technology at all times, since most of the time, it's a developer that's *really* writing the tests.
|
14
|
+
|
15
|
+
With these ideas in mind, what Spectie provides is:
|
16
|
+
|
17
|
+
* A small number of methods on top of RSpec for making your integration tests readable. This isn't much more than "Given/When/Then".
|
18
|
+
* A configuration and mapping layer for different integration testing code, such as what's provided by ActionController's integration.rb, or the Ruby client for Selenium.
|
19
|
+
* Common functionality for supported integration testing solutions, such as the option to restart the Selenium browser between tests, or simply clear the cookies.
|
20
|
+
|
21
|
+
Advantages of having your integration tests written with Spectie:
|
22
|
+
|
23
|
+
* It's Ruby.
|
24
|
+
* If you're familiar with RSpec already, all the same functionality is available.
|
25
|
+
* All new syntax beyond RSpec is kept to a minimum, and exists solely to facilitate developer-driven BDD.
|
26
|
+
* Use familiar methods for code navigation and reuse.
|
27
|
+
|
28
|
+
== Example
|
29
|
+
=== Rails
|
30
|
+
Feature "Compelling Feature" do
|
31
|
+
Scenario "As a user, I would like to use a compelling feature" do
|
32
|
+
Given :i_have_an_account
|
33
|
+
And :i_have_logged_in
|
34
|
+
|
35
|
+
When :i_access_a_compelling_feature
|
36
|
+
|
37
|
+
Then :i_am_presented_with_stunning_results
|
38
|
+
end
|
39
|
+
|
40
|
+
def i_have_an_account
|
41
|
+
@user = create_user
|
42
|
+
end
|
43
|
+
|
44
|
+
def i_have_logged_in
|
45
|
+
log_in_as @user
|
46
|
+
end
|
47
|
+
|
48
|
+
def i_access_a_compelling_feature
|
49
|
+
get compelling_feature_path
|
50
|
+
response.should be_success
|
51
|
+
end
|
52
|
+
|
53
|
+
def i_am_presented_with_stunning_results
|
54
|
+
response.should have_text("Simply stunning!")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
== Installation
|
59
|
+
|
60
|
+
=== Gem
|
61
|
+
sudo gem install spectie
|
62
|
+
|
63
|
+
=== Rails plugin
|
64
|
+
script/plugin install git://github.com/ryankinderman/spectie.git
|
65
|
+
|
66
|
+
=== Git
|
67
|
+
git clone git://github.com/ryankinderman/spectie.git
|
68
|
+
|
69
|
+
== Configuration
|
70
|
+
=== Ruby on Rails
|
71
|
+
In <em>spec/spec_helper.rb</em>, after <tt>require 'spec/rails'</tt>, add:
|
72
|
+
require 'spectie/rails'
|
73
|
+
|
74
|
+
That's it. Spectie registers itself with RSpec, so you can run your integration tests with the usual <tt>rake spec:integration</tt> command. Also, all of the usual methods in a {Rails integration testing session}[http://api.rubyonrails.org/classes/ActionController/Integration/Session.html] are available for you to use as well.
|
75
|
+
|
76
|
+
=== Selenium
|
77
|
+
TODO
|
78
|
+
|
79
|
+
== Author
|
80
|
+
|
81
|
+
Ryan Kinderman (ryan@kinderman.net)
|
82
|
+
|
83
|
+
== Copyright
|
84
|
+
|
85
|
+
Copyright (c) 2009 Ryan Kinderman. See LICENSE for details.
|
data/Rakefile
ADDED
data/VERSION.yml
ADDED
data/initialize.rb
ADDED
data/lib/spectie.rb
ADDED
data/lib/spectie/main.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Spectie
|
2
|
+
module Main
|
3
|
+
# Creates an example group for the feature.
|
4
|
+
# Feature "User Authentication" do
|
5
|
+
# Scenario "As a user without an account, I want to create one so that I can log in" do
|
6
|
+
# Given :i_do_not_have_an_account
|
7
|
+
# And :i_want_to_log_in
|
8
|
+
#
|
9
|
+
# When :i_create_an_account
|
10
|
+
#
|
11
|
+
# Then :i_can_log_in
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def i_do_not_have_an_account
|
15
|
+
# # ... codey code ...
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # ... remaining scenario statements ...
|
19
|
+
# end
|
20
|
+
def Feature(*args, &block)
|
21
|
+
describe(*args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include Spectie::Main
|
@@ -0,0 +1,55 @@
|
|
1
|
+
###################################################################################
|
2
|
+
# Preserve method_missing from rspec, which supports the general
|
3
|
+
# be_ and have_ predicate matchers. This method gets overridden for
|
4
|
+
# Rails integration tests by ActionController::IntegrationTest for
|
5
|
+
# session delegation.
|
6
|
+
require "spec/interop/test/unit/testcase"
|
7
|
+
Test::Unit::TestCase.class_eval do
|
8
|
+
alias_method :method_missing_from_rspec, :method_missing
|
9
|
+
end
|
10
|
+
|
11
|
+
require "action_controller/integration"
|
12
|
+
ActionController::IntegrationTest.class_eval do
|
13
|
+
alias_method :method_missing_from_rails, :method_missing
|
14
|
+
def method_missing(*args, &block)
|
15
|
+
method_missing_from_rspec(*args, &block)
|
16
|
+
rescue NameError
|
17
|
+
method_missing_from_rails(*args, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
###################################################################################
|
21
|
+
begin
|
22
|
+
spec_rails_path = "spec/rails"
|
23
|
+
require spec_rails_path
|
24
|
+
rescue LoadError => e
|
25
|
+
if e.message =~ /#{Regexp.escape(spec_rails_path)}$/
|
26
|
+
raise "RSpec-Rails not available. Install it with sudo gem install rspec-rails"
|
27
|
+
else
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
ActionController::IntegrationTest.class_eval do
|
33
|
+
alias_method :orig_initialize, :initialize
|
34
|
+
def initialize(*args)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Spectie
|
40
|
+
|
41
|
+
class RailsStoryExampleGroup < ActionController::IntegrationTest
|
42
|
+
include StoryExampleGroupMethods
|
43
|
+
|
44
|
+
# The following line ensures that RailsStoryExampleGroup is, by
|
45
|
+
# default, the lowest point in the example group hierarchy that
|
46
|
+
# helper modules will be included.
|
47
|
+
#
|
48
|
+
# If that doesn't make sense, just comment this line
|
49
|
+
# out and observe the failing test.
|
50
|
+
Spec::Example::ExampleGroupFactory.default(self)
|
51
|
+
Spec::Example::ExampleGroupFactory.register(:integration, self)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spectie
|
2
|
+
module Configuration
|
3
|
+
class Selenium
|
4
|
+
attr_writer :driver_options
|
5
|
+
attr_accessor :start_browser_once, :controlled
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.start_browser_once = true
|
9
|
+
self.controlled = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def driver_options
|
13
|
+
@driver_options || raise("No Selenium driver options specified")
|
14
|
+
end
|
15
|
+
|
16
|
+
def controlled?
|
17
|
+
self.controlled == true
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def selenium
|
23
|
+
@selenium ||= Selenium.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
::Spec::Runner.send :include, Configuration
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
begin
|
2
|
+
selenium_client_path = "selenium/client"
|
3
|
+
require selenium_client_path
|
4
|
+
rescue LoadError => e
|
5
|
+
if e.message =~ /#{Regexp.escape(selenium_client_path)}$/
|
6
|
+
raise "selenium-client not available. Install it with sudo gem install selenium-client"
|
7
|
+
else
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Spectie
|
13
|
+
class SeleniumStoryExampleGroup
|
14
|
+
include StoryExampleGroupMethods
|
15
|
+
include Selenium::Client::SeleniumHelper
|
16
|
+
|
17
|
+
selenium = nil
|
18
|
+
selenium_config = Spec::Runner.configuration.selenium
|
19
|
+
|
20
|
+
before :suite do
|
21
|
+
if selenium_config.controlled? and selenium_config.start_browser_once
|
22
|
+
selenium = Selenium::Client::Driver.new(selenium_config.driver_options)
|
23
|
+
selenium.start
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
after :suite do
|
28
|
+
if selenium_config.controlled? and selenium_config.start_browser_once
|
29
|
+
selenium.stop
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
before :each do
|
34
|
+
if selenium_config.controlled? and !selenium_config.start_browser_once
|
35
|
+
selenium = Selenium::Client::Driver.new(selenium_config.driver_options)
|
36
|
+
selenium.start
|
37
|
+
end
|
38
|
+
@selenium = selenium
|
39
|
+
end
|
40
|
+
|
41
|
+
after :each do
|
42
|
+
if selenium_config.controlled?
|
43
|
+
if selenium_config.start_browser_once
|
44
|
+
selenium.delete_all_visible_cookies
|
45
|
+
else
|
46
|
+
selenium.stop
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Spectie
|
2
|
+
|
3
|
+
module StoryExampleGroupMethods
|
4
|
+
def self.included(mod)
|
5
|
+
mod.class_eval do
|
6
|
+
extend Spec::Example::ExampleGroupMethods
|
7
|
+
include Spec::Example::ExampleMethods
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def scenario_methods; [:Given, :When, :Then, :And] end
|
12
|
+
|
13
|
+
# Creates a scenario example within a feature (see Spectie::Main#Feature).
|
14
|
+
def Scenario(description, options={}, backtrace=nil, &implementation)
|
15
|
+
example(description, options, backtrace) do
|
16
|
+
instance_eval &implementation
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Disables a scenario.
|
21
|
+
def xScenario(description, options={}, &implementation)
|
22
|
+
xexample description, options, &implementation
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
scenario_methods.each do |scenario_method|
|
28
|
+
method = <<-METHOD
|
29
|
+
def #{scenario_method}(statement, *args, &block)
|
30
|
+
send statement, *args, &block
|
31
|
+
end
|
32
|
+
METHOD
|
33
|
+
|
34
|
+
class_eval method, __FILE__, __LINE__
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
namespace :package do
|
2
|
+
begin
|
3
|
+
require 'jeweler'
|
4
|
+
Jeweler::Tasks.new do |gem|
|
5
|
+
gem.name = %q{spectie}
|
6
|
+
gem.summary = %q{A Ruby integration testing framework written on top of RSpec.}
|
7
|
+
gem.description = <<-EOF
|
8
|
+
Spectie (rhymes with "necktie") is a pure Ruby acceptance testing framework for RSpec.
|
9
|
+
The philosophy of Spectie is that, since the business stakeholders on most projects
|
10
|
+
don't care about exactly how you test, you're free to write the acceptance tests on
|
11
|
+
a project how *you*, the developer, need to in order to ensure that the implementation
|
12
|
+
is correct, easily understood, and maintainable. Furthermore, since you're a developer,
|
13
|
+
the easiest, most straight-forward and maintainable way for you to write your tests is
|
14
|
+
by using the highly expressive language that you're already coding in for the project;
|
15
|
+
that's Ruby, baby!
|
16
|
+
EOF
|
17
|
+
gem.platform = Gem::Platform::RUBY
|
18
|
+
gem.required_ruby_version = '>= 1.8.6'
|
19
|
+
gem.add_dependency('rspec', '>= 1.2.7')
|
20
|
+
|
21
|
+
gem.authors = ["Ryan Kinderman"]
|
22
|
+
gem.date = Time.now.strftime("%Y-%m-%d")
|
23
|
+
gem.email = %q{ryan@kinderman.net}
|
24
|
+
gem.homepage = %q{http://github.com/ryankinderman/spectie}
|
25
|
+
gem.rubyforge_project = %q{kinderman}
|
26
|
+
|
27
|
+
gem.has_rdoc = true
|
28
|
+
gem.rdoc_options = ["--charset=UTF-8"]
|
29
|
+
gem.extra_rdoc_files = [
|
30
|
+
"LICENSE",
|
31
|
+
"README.rdoc"
|
32
|
+
]
|
33
|
+
|
34
|
+
gem.require_paths = ["lib"]
|
35
|
+
gem.files = Dir["**/*"]
|
36
|
+
gem.files.reject! { |f| !f.match(/^(vendor|pkg)(\/|$)/).nil? }
|
37
|
+
gem.test_files = Dir["spec/**/*_spec.rb"]
|
38
|
+
|
39
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
40
|
+
end
|
41
|
+
|
42
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
43
|
+
rubyforge.doc_task = "rdoc"
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
puts "Jeweler not available. It's only needed if you're going to build the gem for this library. Install it with something like: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Cleans the project package artifacts, generates all files needed to build the gem, and builds it"
|
50
|
+
task :full => ["clean", "rdoc", "gemspec", "build"]
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rake/rdoctask'
|
2
|
+
Rake::RDocTask.new do |rdoc|
|
3
|
+
if File.exist?('VERSION.yml')
|
4
|
+
config = YAML.load(File.read('VERSION.yml'))
|
5
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
6
|
+
else
|
7
|
+
version = ""
|
8
|
+
end
|
9
|
+
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = "spectie #{version}"
|
12
|
+
rdoc.rdoc_files.include('README*')
|
13
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'rake/contrib/sshpublisher'
|
18
|
+
namespace :rubyforge do
|
19
|
+
|
20
|
+
desc "Release gem and RDoc documentation to RubyForge"
|
21
|
+
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
22
|
+
|
23
|
+
namespace :release do
|
24
|
+
desc "Publish RDoc to RubyForge."
|
25
|
+
task :docs => [:rdoc] do
|
26
|
+
config = YAML.load(
|
27
|
+
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
28
|
+
)
|
29
|
+
|
30
|
+
host = "#{config['username']}@rubyforge.org"
|
31
|
+
remote_dir = "/var/www/gforge-projects/spectie/"
|
32
|
+
local_dir = 'rdoc'
|
33
|
+
|
34
|
+
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
40
|
+
end
|