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

Hello,

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

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

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

You can use assert_* freely in specify-blocks; Object#should works in
Test::Unit test cases, too, but doesn’t increase the assertion count.

== 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.?)
  • should.output, to check what is printed

== 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 (e.g. see SPECS):

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

== Thanks to

  • Eero S. for writing should.output.
  • 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 (C) 2006 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.1 at

    http://chneukirchen.org/releases/testspec-0.1.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

Happy hacking and have a nice day,
Christian N.

9861cf92ec39cce7a5e96504f1fdb6f0 testspec-0.1.0.tar.gz

On 9/29/06, Christian N. [email protected] wrote:

Hello,

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

What a nice coincidence ;=)

will try it soon.

Robert


Deux choses sont infinies : l’univers et la bêtise humaine ; en ce qui
concerne l’univers, je n’en ai pas acquis la certitude absolue.

  • Albert Einstein

On 9/29/06, Christian N. [email protected] wrote:

Hello,
[snip]
You can use assert_* freely in specify-blocks; Object#should works in
Test::Unit test cases, too, but doesn’t increase the assertion count.
[/snip]
Happy hacking and have a nice day,
Christian N.

9861cf92ec39cce7a5e96504f1fdb6f0 testspec-0.1.0.tar.gz

Christian N. [email protected] http://chneukirchen.org

Looks very interesting.

Is there a reason that calls to “should” don’t increase the assertion
count? Seeing as they are sort of equivalent, and seeing the
assertion count is a helpful thing, it would be nice. Or maybe there
should be a general “verification count” that includes calls to
should?

Here is one hack to do the assertion counts, btw:

  • rob

On 10/3/06, Rob S. [email protected] wrote:

9861cf92ec39cce7a5e96504f1fdb6f0 testspec-0.1.0.tar.gz
should?

Interesting. We use an ad-hoc #should for BDD where I work:

(in our Rails test_helper.rb ):

class Test::Unit::TestCase
def self.should(behave,&block)
mname = “test_should_#{behave}”
if block
define_method mname, &block
else
define_method mname do
flunk “#{self.class.name.sub(/Test$/,‘’)} should #{behave}”
end
end
end
end

This allows us to write tests as such:

should “open the index page” do
get ‘/’
assert_response :success
end

As the method name is prefixed by ‘test_’ it does get counted in the
assertion count. If you’ll notice, too, the method name actually gets
defined as:

‘test_should_open the index page’

which because of the way the method is created and called, is never a
problem with the parser and makes for easier to read error messages.
Maybe
you can use this to help with counting your ‘shoulds’ in this library.

Jason

“Rob S.” [email protected] writes:

Here is one hack to do the assertion counts, btw:
404 Error - Page Not Found...

This hack is done by the context/specify blocks, inside them, #shoulds
are counted. However, I didn’t want to monkeypatch Test::Unit
directly, so #shoulds in “ordinary” Test::Unit test_* method won’t be
counted.

Since you usually want to use context/specify blocks, this is not a
problem in practice.