Rspec-Given

Testing is a Given

I have played with a lot of testing frameworks. We Rubyists are forever obsessing about our testing. Be it testing like Usain Bolt or the TSA, either way, we be testing. And that is a very good thing.

I subscribe heavily to making my code as readable and understandable as possible. I, for one, read more code than I write. The first place I always look is the tests. The integration and functional tests give me the 10,000 foot view of the context, the units tests tell me about the mechanics and edge cases. And being a developer of this ilk, I strive to make my tests as expressive as possible for the next developer following my code story. Gone are the days of information hoarding and being the specialist in that piece of code. Leave that to those other devs. Don’t be that guy.

Lately I have been toying with the rspec-given extension for Rspec from none other that Jim Weirich ( and I’m pretty sure I don’t have to tell you who he is). We all know the expressive syntax sugar we get from Rspec, and we may like the clarity of a Cucumber features. rspec-given brings those Given, When, Then declarations into your tests, along with a couple of extras that certainly hit my happy gong.

The Basics

Getting rspec-given into your specs is trivial, just add the gem to your Gemfile and require it in the spec_helper.rb a la:

And then you are all set for the new hotness in declarative syntax that really implies the intent of the code under test.

The syntax follows the Given/When/Then philosophy of Given being setup, When being exercising or ‘poking’ and Then for expectations and assertions.

An example of the syntax would be as follows:

You will note the absence of a When block here as we are only testing state, the number of beers on the wall, initially. Using the familiar Rspec describe and context blocks define what we are testing. The Given block takes an optional symbol, which if you are a regular user of Rspec will be familiar, to let(:something){ lazily_evaluate_to_something_else}. You will note the snazzy new Rspec expectation and assertion syntax being used in the Then block.

On a side note, I have never really liked using the word “should” in my tests. I realise that, yes, we are writing it before the implementation so we are looking to the future of the code’s capabilities. I don’t know, it feels a bit fuzzy and almost OK if what I’m testing is only correct some of the time? When writing a specification of how my code should behave, I like Test::Unit‘s assert this is that, and now mintiest uses must_*. These are clear expectations for the code, far superior to should.

Poking and What Not

Now we have tested some state in our code it is time to exercise a piece of code and test the output. Here we use the When syntax.

Putting aside the fact that I’m describing not only being a famous drinking rhyme, you can read that test and know exactly what we are trying to achieve. Setup, Poke, Assert. Of course This is clearly a simple example, but we can extend this with multiple setups across multiple blocks of context.

Rspec-given also brings with it an And syntax (Note: I had to use the latest beta to get this syntax, 2.1.0.beta.4). At first glance And looked an alias of Then until you read the documentation. Yes it is a Then assertion, only it will re-use the setup of the mandatory Then that precedes it. Thus, when you have a lengthy setup, tested your first assertion, and wish to further test state without repeating the setup, And is your friend. What immediately springs to mind is when I parse CSV files, I can run the setup just once and test every entry without ever re-running the initial setup. Hardly a lengthy setup involved, but certainly nice to remove scaffolding a new test when we have the require state to hand.

Another nice feature of rspec-given is the Invariant syntax. This block is another Then assertion that is injected into every context applicable to it. Invariant is meant to test conditions which remain constant throughout the code under test. If we return to our beer drinking song, we could write:

But, you know what? I rather wouldn’t. Don’t get me wrong, the concept of Invariant is great and when used in a better context than beer songs it can be really helpful. No, for beers songs I, personally would rather sacrifice syntax for readability and create a new context of the test (while showing how easy it is to modify your setup within different contexts).

If we look to the Rspec-Given documentation we see a much more applicable example, where the assertion is far clearer.

From that point on you can get testing in earnest. The personal highlight has to be the simplification of setups, especially across context. With pure Rspec I would write:

By comparing the two, we can see how much is omitted. The it blocks become unnecessary noise and to dry up the test code we would have to refactor the setup into a method or helper, setting up parameters and so on. Using the Given syntax not only shortens the code but gives it a far more implicit nature.

Going Just a Bit Deeper

Another highlight of rspec-given for me is how it doesn’t monkey patch anything in Rspec. It is written as an extension. I have gone as far as creating custom helpers and assertions for Rspec, but I have never really extended it in any way.

If we look at the configuration for rspec-given we can see it pulling on the power of the existing Domain Specific Language (DSL).

It uses extend and include methods on the Rspec::Core::Configuration instance. These are pretty similar in function where extend adds to the example groups (describe and context) and include to the examples (it blocks). This in itself is a really neat feature of Rspec and something I will be playing with in the future, all thanks to rspec-given.

Wrapping up

In my opinion rspec-given is a very welcome addition to the Rspec suite. Of all the developers I know using it (and to be fair that isn’t many at the moment) all have very good things to say about it. It’s a pretty compact little extension that provides a heck of a lot for spec suites. I have found, in general, the specs are much tidier and really relay the intent of the code. These are very useful aspects of a DSL which we should all aspire to creating.

The added benefit has been showing what a full-featured test framework Rspec is. Steven Baker and David Chelimsky have really done a great job building the framework to be so flexible. How easily Jim has hooked into Rspec’s DSL and brought out some really impressive syntax keeps me awake at night cursing all their names for being so damn good.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.