Share this article

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: [gist id=3889881] 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: [gist id=3889895] 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. [gist id=3889900] 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. [gist id=3889903] 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: [gist id=3889906] 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). [gist id=3889910] If we look to the Rspec-Given documentation
we see a much more applicable example, where the assertion is far clearer. [gist id=3889912] 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: [gist id=3889914] 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). [gist id=3889919] 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.

Frequently Asked Questions about RSpec-Given

What is the main purpose of RSpec-Given?

RSpec-Given is a tool used in Ruby programming for behavior-driven development (BDD). It provides a more natural syntax for setting up test preconditions (Given), actions (When), and postconditions (Then). This makes your tests more readable and easier to understand, as they follow a logical, narrative-like structure.

How does RSpec-Given differ from other testing frameworks?

Unlike traditional testing frameworks that use setup, action, and assertion steps, RSpec-Given uses Given/When/Then clauses. This makes your tests more declarative and less procedural, which can lead to cleaner, more maintainable code. It also encourages a more behavior-driven approach to testing, focusing on the behavior of the system rather than its implementation details.

Can I use RSpec-Given with other testing libraries?

Yes, RSpec-Given is designed to work seamlessly with other RSpec libraries, such as RSpec-Expectations and RSpec-Mocks. This allows you to leverage the full power of RSpec’s testing ecosystem while benefiting from the readability and expressiveness of Given/When/Then clauses.

Is there a Python equivalent for RSpec-Given?

Yes, there is a Python equivalent for RSpec-Given called Pytest-Given. It provides similar functionality, allowing you to write tests in a Given/When/Then format. However, it’s important to note that the syntax and usage may differ slightly due to the differences between Ruby and Python.

How do I install RSpec-Given?

You can install RSpec-Given by adding it to your Gemfile and running the bundle install command. Alternatively, you can install it directly using the gem install rspec-given command. Once installed, you can require it in your spec files with require 'rspec/given'.

How do I use RSpec-Given in my tests?

To use RSpec-Given, you start by defining a Given clause for your test setup, followed by a When clause for the action, and finally a Then clause for the assertion. Each clause is defined using the corresponding Given, When, and Then methods provided by RSpec-Given.

Can I use RSpec-Given for integration tests?

Yes, RSpec-Given can be used for both unit tests and integration tests. However, it’s particularly well-suited for unit tests, as it encourages a more granular, behavior-driven approach to testing.

What are the benefits of using RSpec-Given?

RSpec-Given can make your tests more readable, maintainable, and expressive. It encourages a behavior-driven approach to testing, which can lead to more robust, reliable tests. It also integrates seamlessly with other RSpec libraries, allowing you to leverage the full power of RSpec’s testing ecosystem.

Are there any limitations or drawbacks to using RSpec-Given?

While RSpec-Given offers many benefits, it may not be suitable for all testing scenarios. For example, it may not be the best choice for highly procedural tests, or tests that require complex setup or teardown steps. It’s also a bit more verbose than traditional RSpec syntax, which may be a drawback for some developers.

Where can I find more information about RSpec-Given?

You can find more information about RSpec-Given on its GitHub page, as well as in various online tutorials and blog posts. The RSpec-Given documentation is also a great resource, providing detailed information on its usage and features.

Dave KennedyDave Kennedy
View Author

Dave is a web application developer residing in sunny Glasgow, Scotland. He works daily with Ruby but has been known to wear PHP and C++ hats. In his spare time he snowboards on plastic slopes, only reads geek books and listens to music that is certainly not suitable for his age.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form