Test/spec 0.3, a BDD interface for Test::Unit


#1

Hello,

today I’m releasing test/spec 0.3, a library to do BDD with Test::Unit.

(See below for changes in version 0.3.)

== 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

test/spec does not include a mocking/stubbing-framework; use whichever
you like to—FlexMock and Mocha have been tested.

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.)

== 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

== Additional assertions

These assertions are not included in Test::Unit, but have been added
to test/spec for convenience:

  • should.not.satisfy
  • a.should. (works like assert a.?)
  • a.should.be (where is <, <=, >, >=, or ===)
  • should.output, to check what is printed

== 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:

spec.output
- works for print
- works for puts
- works with readline

RDox, run with --runner=rdox (or -rr) can be included for RDoc
documentation:

== spec.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

== Disabled specifications

Akin to the usual Test::Unit practice, tests quickly can be disabled
by replacing specify with xspecify. test/spec will count the
disabled tests when you run it with SpecDox or RDox.

== 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

See specrb --help for the usage.

== Changes in version 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.

== Installing with RubyGems

Since version 0.3, a Gem of test/spec is available. You can install
with:

gem install test-spec

(It may take some time for the index to be updated and the mirrors
propagated.) 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

== Roadmap

Version 1.0 (February 2006):: first stable release.

== Contact

Please mail bugs, suggestions and patches to
mailto:removed_email_address@domain.invalid.

Darcs repository (“darcs send” is welcome for patches):
http://chneukirchen.org/repos/testspec

== Thanks to

  • Eero S. for writing should.output.
  • Jean-Michel Garnier for packaging the first gem.
  • Mikko L., Jan Wikholm, Matt M. and Michael F. for
    testing the gem.
  • Thomas F. for script.aculo.us BDD testing which convinced me.
  • Dave A. for BDD.
  • The RSpec team for API inspiration.
  • Nathaniel T. for Test::Unit.

== Copying

Copyright © 2006, 2007 Christian N.
http://purl.org/net/chneukirchen
test/spec is licensed under the same terms as Ruby itself.

== Where can I get it?

You can download test/spec 0.3 at

    http://chneukirchen.org/releases/test-spec-0.3.0.tar.gz

Alternatively, you can checkout from the development repository with:

       darcs get http://chneukirchen.org/repos/testspec

(Patches using “darcs send” are most welcome.)

== 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/

Happy hacking and have a nice day,

Christian N. removed_email_address@domain.invalid http://chneukirchen.org

ea043ab5837994179d4659aa1e2fcc88 test-spec-0.3.0.tar.gz
d0e1c45c2e814cc26a7967232ca99f6c test-spec-0.3.0.gem


#2

Christian N. wrote:

test/spec does not include a mocking/stubbing-framework; use whichever
you like to—FlexMock and Mocha have been tested.

test/spec has no dependencies outside Ruby 1.8.

The test-spec gem does seem to depend on both FlexMock and Mocha. Not
complaining, I would have grabbed them anyway.


#3

On 24 Jan, 21:29, Joel VanderWerf removed_email_address@domain.invalid wrote:

Christian N. wrote:…

test/spec has no dependencies outside Ruby 1.8.

The test-spec gem does seem to depend on both FlexMock and Mocha. Not
complaining, I would have grabbed them anyway.

Both of which (for me at least) had to be installed before test/spec:

[1807] sudo gem update
Updating installed gems…
Need to update 18 gems from http://gems.rubyforge.org

complete
Gems: [] updated
[1808] sudo gem install test-spec --source
http://chneukirchen.org/releases/gems
Install required dependency flexmock? [Yn]
ERROR: While executing gem … (Gem::GemNotFoundException)
Could not find flexmock (>= 0.4.1) in the repository

YMMV

Allan


#4

Joel VanderWerf removed_email_address@domain.invalid writes:

Christian N. wrote:

test/spec does not include a mocking/stubbing-framework; use whichever
you like to—FlexMock and Mocha have been tested.
test/spec has no dependencies outside Ruby 1.8.

The test-spec gem does seem to depend on both FlexMock and Mocha. Not
complaining, I would have grabbed them anyway.

That (optional) dependency will be removed in the next release.


#5

Allan wrote:

Could not find flexmock (>= 0.4.1) in the repository

That’s odd. I installed from the default source, and said “Y” to both
dependencies, and it worked.

Maybe in your case it was looking for flexmock in the chneukirchen.org
source?