Hope Ol’ Stan Lee doesn’t have that “friendly, neighborhood” bit trademarked… ah well… life is to short to worry about such things.
Welcome to your whirlwind tour of RSpec, a Behavior Driven Development framework for Ruby and Ruby on Rails. I debated with myself on how best to start this series of tutorials, and eventually decided to take a breadth-first approach, i.e. dump it all in your lap and break it down from there. So this first post we’ll cover just what RSpec is and what it can do for you and your code.
Since RSpec is simply an implementation of Behavior Driven Development, you’d be best served to read my previous post An Introduction to Behavior Driven Development first, if you don’t know what that is.
Getting back to RSpec. RSpec, in addition to being an implementation of BDD, is more specifically, a DSL, or Domain Specific Language. Which, itself, is a fancy way of saying that it is a programming language designed for a specific purpose or task: namely, the task of specifying the behavior of an application. The programming language part may be a bit obtuse in meaning; it’s not another C or Java or VisualBasic. However, it does introduce a new ‘language’ in Ruby that is specific to defining application behavior.
Now that you know what it is, let’s get to the fun stuff and see what it can do.
I’ve already stated that RSpec’s purpose is to specify the behavior of an application. More to the point, RSpec provides a way for us to set down in stone exactly what our application should do and how it should behave. Notice the emphasis on ’should’. ‘Should’ is a crucial focal point of BDD and it’s how RSpec makes its assertions.
For example, if I wanted to specify that a post should have a title, I would write something a little like this:
There’s actually quite alot going on there, so let’s break it down.
We start with creating a describe block, which encapsulates our specification. The part right after describe is the name of the class we are describing, in this case: Post.
Then, we have a before(:each) block, which acts as a setup method or initializer for the specification. The :each specifies that we want the following instructions performed for every example. Inside this block, we store a new instance of the Post class in the instance variable, @post.
Next, we add an it block, which tells RSpec we’re starting an example. The example, itself, is everything between the do and end. The string after it, “should have a title”, is purely informational. You could even leave it out. In which case, RSpec would automatically generate a description of the example based on what is inside. In this case, that would end up being, “title should not be blank”.
Inside the it block, we have the real meat of our example. We access the title attribute and specify that it should_not be_blank.
should_not is a method RSpec extends the superclass Object with; should_not and it’s positive version should will both return true or false, resulting in either a pass or fail, respectively, for our example.
be_blank is bit of a different beast. It is not a method itself, but rather signals to RSpec to call the blank? method on our title attribute. blank?, by the way, is an innate method (exists out of the box) that returns true if the variable in question is either an empty string or nil.
Every example you code in RSpec will have at least one statement with should or should_not. The be_whatever part is just one of many different possible arguments (matchers) for these two methods. Let’s look at the full list:
Eql and Equal
RSpec has two levels of equality checks. First, you can use eql or the standard equality operator ==. For example:
"this string".should eql "this string" or "this string".should == "this string"
Second, you can check for equality at the object level with equal or the “three equals” operator ===. For example:
25.should equal 25 or 25.should === 25
However, note:
"this string".should equal "this string" and "this string".should === "this string"
Both of these will actually evaluate to false. To understand why you could run script/console and try the following:
$ ruby script/console Loading development environment. >> "this string".object_id => 106148390 >> "this string".object_id => 106145680
Even though it’s the same string, each instance has a unique object id. The example using 25 works because of the following:
$ ruby script/console Loading development environment. >> 25.object_id => 51 >> 25.object_id => 51
The technical explanation is that 25 is instantiated as a Fixnum, so every instance of 25 afterwards is actually a reference to the first instance of 25. However, strings and most other objects in Ruby receive unique ids for every instance.
Have
Quite often, you’ll want to ensure that a collection has at least a certain number of items: ensuring there are no validation errors on a particular field in a form, for example. RSpec provides an easy way to specify the behavior you want with have. For example:
day.should have(24).hours
It should be noted that in order for this to work, day would have to own a collection, hours, with 24 items. This is really just shorthand for the following:
day.hours.should have(24).items
RSpec provides some “sugar” with have so that both of the following will work without any further implementation:
[1, 2, 3].should have(3).items and "fun".should have(3).characters
Additionally, some things in RSpec exist simply for the purpose of readability. One example of this is have_exactly, which is just an alias for have. So, the code above could be be rewritten as:
day.should have_exactly(24).hours
Either way works; it’s simply a matter of preference.
Often, you won’t be entirely sure about how many items you should have, but you will know a minimum or maximum. Once again, RSpec comes through with have_at_least and have_at_most. For example:
blog.should have_at_least(1).post or question.should have_at_most(4).answer_choices
Include
Closely related to have, we have include. Whereas, have concerns itself with the number of items in a collection, include concerns itself with the collection’s values. For example:
{ :str1 => 'first string', :str2 => 'second string' }.should include('second string')
The above would pass because the value ’second string’ exists in the the collection. You can even specify multiple values as such:
[1, 2, 3, 4, 5].should include(1, 3, 5)
However, when you specify multiple values for the include all of those values must be present in order for the example to pass. The following would fail, since 6 is not present in the array:
[1, 2, 3, 4, 5].should include(2, 4, 6)
Match
RSpec provides the ability to match based on regular expressions through the match matcher. Like eql and equal before, there’s you can also the use the operator equivalent, =~. For example:
"sample string".should match(/sample/) or "sample string".should =~ /sample/
Predicates
The previous matchers have all been methods specific to RSpec. The true power of RSpec comes from letting you apply its behavior-specific language to your own methods. It does this via various prefixes. We encountered one of these earlier with be_blank. As we saw, the actual method being called is blank?, but by prefixing it with be_ we can not only instruct RSpec to call this method, but also maintain nicer readability. Here are some other common uses of the be_ prefix:
be_true
be_false
be_nil
be_blank
be_empty
be_an_instance_of(Class)
be_a_kind_of(Class)
be_close(expected, delta)
Each of the above rely on built in Ruby methods, but you can also apply this to any other predicate. What is a predicate? Predicates are methods that end with ?’s and return true or false. It could be one built into Ruby or Ruby on Rails, or it could be one of your own creation. Consider the following:
…
Also, notice the two matchers above, be_a_kind_of and be_an_instance_of. These respectively call the methods kind_of? and instance_of?. The prefixes be_a_ and be_an_ are aliases of be_, provided for better readability.
In addition to the be_ prefix, RSpec also provides the have_ prefix. Note, however, that this is not the same as the have matcher mentioned above. It’s also not a prefix in the truest since, but the best way to explain is with an example:
{:fun => 1, :times => 2 }.should have_key(:fun)
In this example have_key signals RSpec to call the predicate has_key? built into Ruby. This will work with any predicate starting with has_ as well. For example:
…
Is that it?
There’s a few other matchers that I have intentionally not mentioned yet: only because they are a little more abstract in nature. We’ll eventually get to all those as we continue through this series.
The next article up will detail the process of spec’ing a model. I haven’t completely decided on an example application yet, but I have a couple ideas.
Tags: bdd, rspec, ruby on rails
Subscribe (RSS)