Bacon – small RSpec clone.

"Truth will sooner come out from error than from confusion."
                                            ---Francis Bacon

Bacon is a small RSpec clone weighing less than 300 LoC but nevertheless providing all essential features.

Whirl-wind tour

require 'bacon'

describe 'A new array' do
  before do
    @ary = Array.new
  end

  it 'should be empty' do
    @ary.should.be.empty
    @ary.should.not.include 1
  end

  it 'should have zero size' do
    @ary.size.should.equal 0
    @ary.size.should.be.close 0.1, 0.5
  end

  it 'should raise on trying fetch any index' do
    lambda { @ary.fetch 0 }.
      should.raise(IndexError).
      message.should.match(/out of array/)

    # Alternatively:
    should.raise(IndexError) { @ary.fetch 0 }
  end

  it 'should have an object identity' do
    @ary.should.not.be.same_as Array.new
  end

  # Custom assertions are trivial to do, they are lambdas returning a
  # boolean vale:
  palindrome = lambda { |obj| obj == obj.reverse }
  it 'should be a palindrome' do
    @ary.should.be.a palindrome
  end

  it 'should have super powers' do
    should.flunk "no super powers found"
  end
end

Now run it:

$ bacon whirlwind.rb
A new array
- should be empty
- should have zero size
- should raise on trying fetch any index
- should have an object identity
- should be a palindrome
- should have super powers [FAILED]

Bacon::Error: no super powers found
	./whirlwind.rb:39: A new array - should have super powers
	./whirlwind.rb:38
	./whirlwind.rb:3

6 specifications (9 requirements), 1 failures, 0 errors

If you want shorter output, use the Test::Unit format:

$ bacon -q whirlwind.rb
.....F
Bacon::Error: no super powers found
	./whirlwind.rb:39: A new array - should have super powers
	./whirlwind.rb:38
	./whirlwind.rb:3

6 tests, 9 assertions, 1 failures, 0 errors

It also supports TAP:

$ bacon -p whirlwind.rb
ok 1        - should be empty
ok 2        - should have zero size
ok 3        - should raise on trying fetch any index
ok 4        - should have an object identity
ok 5        - should be a palindrome
not ok 6    - should have super powers: FAILED
# Bacon::Error: no super powers found
# 	./whirlwind.rb:39: A new array - should have super powers
# 	./whirlwind.rb:38
# 	./whirlwind.rb:3
1..6
# 6 tests, 9 assertions, 1 failures, 0 errors

$ bacon -p whirlwind.rb | taptap -q
Tests took 0.00 seconds.
FAILED tests 6
   6) should have super powers: FAILED

Failed 1/6 tests, 83.33% okay.

(taptap is available from chneukirchen.org/repos/taptap/)

Implemented assertions

  • should.<predicate> and should.be.<predicate>

  • should.equal

  • should.match

  • should.be.identical_to / should.be.same_as

  • should.raise(*exceptions) { }

  • should.change { }

  • should.throw(symbol) { }

  • should.satisfy { |object| }

Added core predicates

  • Object#true?

  • Object#false?

  • Proc#change?

  • Proc#raise?

  • Proc#throw?

  • Numeric#close?

before/after

before and after need to be defined before the first specification in a context and are run before and after each specification.

Shared contexts

You can define shared contexts in Bacon like this:

shared "an empty container" do
  it "should have size zero" do
  end

  it "should be empty" do
  end
end

context "A new array" do
  behaves_like "an empty container"
end

These contexts are not executed on their own, but can be included with behaves_like in other contexts. You can use shared contexts to structure suites with many recurring specifications.

Matchers

Custom matchers are simply lambdas returning a boolean value, for example:

def shorter_than(max_size)
  lambda { |obj| obj.size < max_size }
end

[1,2,3].should.be shorter_than(5)

You can use modules and extend to group matchers for use in multiple contexts.

bacon standalone runner

-s, --specdox            do AgileDox-like output (default)
-q, --quiet              do Test::Unit-like non-verbose output
-p, --tap                do TAP (Test Anything Protocol) output
-o, --output FORMAT      do FORMAT (SpecDox/TestUnit/Tap) output
-a, --automatic          gather tests from ./test/, include ./lib/
-n, --name NAME          runs tests matching regexp NAME
-t, --testcase TESTCASE  runs tests in TestCases matching regexp TESTCASE

If you don’t want to use the standalone runner, run Bacon.summary_on_exit to install an exit handler showing the summary.

Object#should

You can use Object#should outside of contexts, where the result of assertion will be returned as a boolean. This is nice for demonstrations, quick checks and doctest tests.

>> require 'bacon'
>> (1 + 1).should.equal 2
=> true
>> (6*9).should.equal 42
=> false

Thanks to

  • Michael Fellinger, for fixing Bacon for 1.9 and various improvements.

Contact

Please mail bugs, suggestions and patches to <[email protected]>.

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

Copying

Copyright © 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>

Bacon is freely distributable under the terms of an MIT-style license. See COPYING or www.opensource.org/licenses/mit-license.php.

Behavior-Driven Development

<behaviour-driven.org/>

RSpec

<rspec.rubyforge.org/>

test/spec

<test-spec.rubyforge.org/>

Christian Neukirchen

<chneukirchen.org/>