= test/spec, a BDD interface for Test::Unit
=== Copyright (C) 2006, 2007, 2008 Christian Neukirchen mailto:chneukirchen@gmail.com
=== Relevance Fork by Rob Sanheim
== What does this fork add?
This is a fork to add some new features to make the dev experience nicer, and also to DRY up boilerplate
that can appear in test/spec. Note that this is a fork of the 0.4 release, as we haven't merged the 0.9
features back in yet.
Specifically:
-
Rspec style pending specs - leave off the block, and the spec is automatically pending:
it "this is a pending spec"
-
Focused specs - prepend an it
declaration with "f", so it reads fit
, and that spec will run at the exclusion of all others. This is great for use in autotest, when you make a change and ten specs start failing and you want to focus on one spec at a time as you move through them and fix them. For example:
fit "can create things" # test/spec will only run this spec, and ignore all others, until you remove the leading "f"
-
DRY'er, context-aware spec declarations for Rails projects. Very similiar to Rspec's Rails support:
describe UsersController # Subclasses ActionController::TestCase and sets up the UsersController properly
describe UserMailer # Subclasses ActionMailer::TestCase
describe User # Subclasses ActiveSupport::TestCase for model specs
== What is test/spec?
test/spec layers an RSpec-inspired interface on top of Test::Unit, so
you can mix TDD and BDD (Behavior-Driven Development).
test/spec is a clean-room implementation that maps most kinds of
Test::Unit assertions to a `should'-like syntax.
Consider this Test::Unit test case:
class TestFoo < Test::Unit::TestCase
def test_should_bar
assert_equal 5, 2 + 3
end
end
In test/spec, it looks like this:
require 'test/spec'
context "Foo" do
specify "should bar" do
(2 + 3).should.equal 5
end
end
Since test/spec 0.4, you can also use the new RSpec 1.0 style:
require 'test/spec'
describe "Foo" do
it "should bar" do
(2 + 3).should.equal 5
end
end
test/spec does not include a mocking/stubbing-framework; use whichever
you like to. test/spec has been tested successfully with FlexMock and
Mocha.
test/spec has no dependencies outside Ruby 1.8.
== Mixing test/spec and test/unit
test/spec and Test::Unit contexts/test cases can be intermixed freely,
run in the same test and live in the same files. You can just add them
to your Rake::TestTask, too. test/spec allows you to leverage your
full existing Test::Unit infrastructure.
test/spec does not change Test::Unit with the exception of
monkey-patching Test::Unit::TestSuite to order the test cases before
running them. (This should not do any harm, but if you know a way
around it, please tell me.)
test/spec adds three global methods, Object#should, Kernel.context,
and Kernel.describe.
You can use assert_* freely in specify-blocks; Object#should
works in plain Test::Unit test cases, too, but they will not be counted.
== Wrapped assertions
+assert_equal+:: should.equal, should ==
+assert_not_equal+:: should.not.equal, should.not ==
+assert_same+:: should.be
+assert_not_same+:: should.not.be
+assert_nil+:: should.be.nil
+assert_not_nil+:: should.not.be.nil
+assert_in_delta+:: should.be.close
+assert_match+:: should.match, should =
+assert_no_match+:: should.not.match, should.not =
+assert_instance_of+:: should.be.an.instance_of
+assert_kind_of+:: should.be.a.kind_of
+assert_respond_to+:: should.respond_to
+assert_raise+:: should.raise
+assert_nothing_raised+:: should.not.raise
+assert_throws+:: should.throw
+assert_nothing_thrown+:: should.not.throw
+assert_block+:: should.satisfy
(+a+, +an+ and +be+ without arguments are optional and no-ops.)
== Additional assertions
These assertions are not included in Test::Unit, but have been added
to test/spec for convenience:
- should.not.satisfy
- should.include
- a.should.predicate (works like assert
a.predicate?)
- a.should.be operator (where operator is one of >, >=, <, <= or ===)
- should.output (require test/spec/should-output)
If you write an useful general-purpose assertion, I'd like to hear of
it and may add it to the test/spec distribution.
== Messaging/Blaming
With more complex assertions, it may be helpful to provide a message
to show if the assertion has failed. This can be done with the
Should#blaming or Should#messaging methods:
RUBY_VERSION.should.messaging("Ruby too old.").be > "1.8.4"
(1 + 1).should.blaming("weird math").not.equal 11
== Custom shoulds ("Matchers")
To capture recurring patterns in parts of your specifications, you can
define custom "shoulds" (RSpec calls them "matchers") in your
contexts, or include modules of them:
context "Numbers"
class EqualString < Test::Spec::CustomShould
def matches?(other)
object == other.to_s
end
end
def equal_string(str)
EqualString.new(str)
end
specify "should have to_s"
42.should equal_string("42")
end
end
Alternatively, your implementation can define
CustomShould#assumptions, where you can use test/spec assertions
instead of Boolean predicates:
class EqualString < Test::Spec::CustomShould
def assumptions(other)
object.should.equal other.to_s
end
end
A CustomShould by default takes one argument, which is placed in
self.object for your convenience.
You can CustomShould#failure_message to provide a better error
message.
== SpecDox and RDox
test/spec adds two additional test runners to Test::Unit, based on the
console runner but with a different output format.
SpecDox, run with --runner=specdox (or -rs) looks
like RSpec's output:
should.output
- works for print
- works for puts
- works with readline
RDox, run with --runner=rdox (or -rr) can be
included for RDoc documentation (e.g. see SPECS):
== should.output
* works for print
* works for puts
* works with readline
SpecDox and RDox work for Test::Unit too:
$ ruby -r test/spec test/testunit/test_testresult.rb -rs
Test::Unit::TC_TestResult
- fault notification
- passed?
- result changed notification
Finished in 0.106647 seconds.
3 specifications (30 requirements), 0 failures
Since version 0.4, SpecDox and RDox also notice and count empty
specifications.
== Disabled specifications
Akin to the usual Test::Unit practice, tests quickly can be disabled
by replacing +specify+ with +xspecify+ (or +it+ with +xit+).
test/spec will count the disabled tests when you run it with SpecDox
or RDox.
When you use xspecify/xit, you also can drop the block. This is
useful for writing specifications that you haven't yet started
implementing.
Complete contexts can be disabled by using +xcontext+/+xdescribe+.
== Setup/Teardown
Setup/Teardown methods are run in this order:
- before(:all) in order of definition
- before(:each)/setup in order of definition
- specify
- after(:each)/setup in order of definition
- before(:each)/setup in order of definition
- specify
- after(:each)/setup in order of definition
- ...
- after(:all) in order of definition
Please note that before(:all) and after(:all) are run in their own
instance, so all instance variables they set are lost(!) and not
visible to other specifications. They are e.g. useful for setting up
database connections or starting servers.
== Shared contexts
Since version 0.5, you can define shared contexts in test/spec using
shared_context/describe_shared. These contexts are not executed on
their own, but can be included with it_should_behave_like/behaves_like
in other contexts. You can use shared contexts to structure suites
with many recurring specifications.
== specrb
Since version 0.2, test/spec features a standalone test runner called
specrb. specrb is like an extended version of testrb, Test::Unit's
test runner, but has additional options. It can be used for
plain Test::Unit suites, too.
$ specrb -a -s -n should.output
should.output
- works for print
- works for puts
- works with readline
Finished in 0.162571 seconds.
3 specifications (6 requirements), 0 failures
Run specrb --help for the usage.
== test/spec on Rails
If you want to specify your Rails applications, you can use the third-party
plugin "test/spec on Rails", which can be found at:
http://svn.techno-weenie.net/projects/plugins/test_spec_on_rails/
It features testing of model validation, redirection, output, HTTP
status, template rendering and URL generation.
== Installing with RubyGems
Since version 0.3, a Gem of test/spec is available. You can install with:
gem install test-spec
I also provide a local mirror of the gems (and development snapshots)
at my site:
gem install test-spec --source http://chneukirchen.org/releases/gems
== History
-
September 29th, 2006: First public release 0.1.
-
October 18th, 2006: Second public release 0.2.
- Better, module-based implementation
- Official support for FlexMock and Mocha
- More robust Should#output
- Should#operator
- Nested contexts
- Standalone test/spec runner, specrb
-
January 24th, 2007: Third public release 0.3.
- should.be_close, should.be_an_instance_of, should.be_a_kind_of,
and should.be_nil have been deprecated. Use the dot-variants of
them. These assertions will be removed in 1.0.
- specrb -a now includes -Ilib by default for easier out-of-the-box
testing.
- Added custom shoulds.
- Added messaging/blaming.
- Added disabling of specifications.
- Small bug fixes.
- Gem available.
-
June 29th, 2007: Fourth public release 0.4.
- Support for Ruby 1.8.6.
- Support describe/it/before/after RSpec 1.0 syntax.
- Allow should.raise { code_that_raises }
- Add xcontext to disable complete contexts.
- Backtraces are cleaner now.
- Mention test/spec on Rails.
- Fix small Gem bugs.
- Fix bug related to counting negated assertions.
- Fix bug in specrb.
- Allow empty xspecifys.
- Make SpecDox and RDox count empty specifications.
- Allow Kernel#context to take a superclass.
-
XXX, 2007: Fifth public release 0.5.
- Allow should.? as well as should..
- Add shared contexts.
== Contact
Please mail bugs, suggestions and patches to
mailto:chneukirchen@gmail.com.
Darcs repository ("darcs send" is welcome for patches):
http://chneukirchen.org/repos/testspec
Continuous Integration at RunCodeRun:
http://runcoderun.com/relevance/test-spec
== Thanks to
- Eero Saynatkari for writing should.output.
- Tuxie for writing test/spec on Rails.
- Brian Donovan for allowing alternative superclasses.
- Chris Wanstrath for should.raise with a block and xcontext.
- Jean-Michel Garnier for packaging the first gem.
- Mikko Lehtonen, Jan Wikholm, Matt Mower and Michael Fellinger for
testing the gem.
- Chris McGrath for reporting a bug.
- Thomas Fuchs for script.aculo.us BDD testing which convinced me.
- Dave Astels for BDD.
- The RSpec team for API inspiration.
- Nathaniel Talbott for Test::Unit.
== Copying
Copyright (C) 2006, 2007 Christian Neukirchen http://purl.org/net/chneukirchen
test/spec is licensed under the same terms as Ruby itself.
Please mail bugs, feature requests or patches to the mail addresses
found above or use IRC[irc://freenode.net/#ruby-lang] to contact the
developer.
== Links
Behavior-Driven Development:: http://behaviour-driven.org/
RSpec:: http://rspec.rubyforge.org/
script.aculo.us testing:: http://mir.aculo.us/articles/2006/08/29/bdd-style-javascript-testing
FlexMock:: http://onestepback.org/software/flexmock/
Mocha:: http://mocha.rubyforge.org/
Christian Neukirchen:: http://chneukirchen.org/