I just installed RSpec for a project I’m working on. I may be doing things a little bit in reverse since I haven’t written much of any test code and my application is already over the halfway point… It’s a pretty huge project; The half-way point is like 10 miles long already. So now, I’ve got to catch my tests up to my code.
Anyways, I’m not so awesome at Rspec and am just getting a feel for how to do things. I’ve watched part of the Peepcodes, but the rspec ones really don’t hit a sweet spot with me for some reason. Major rails points go to Geoffrey Grosenbach… even though that song he plays during the topic change is annoying.I’ll move on.
After installing Err’s cheat gem, I wondered if there was a cheat for rspec. So i just ran the command:
cheat rspec
And not so much to my surprise, a whole heap of information came up.
Applying what I learned from the cheat sheet, I went ahead and generated an account spec controller. I was also very careful not overwrite my actual account controller by choosing “N” when terminal prompted me. I then went to the spec and decided I would test the methods that did not require authentication. So I picked the easiest one that I saw and the thing is, it stumped me for a few minutes… And then I prevailed.
The method looks like this:
def about_us
@nav = 'about_us'
end
And my test looks like this:
it "should get about us" do
get :about_us
end
Yeah, well that will obviously work because Ruby on Rails has been tested pretty thoroughly… But how do I test that the instance variable “@nav” is actually being set? Turns out there is a handy method that looks like this:
assigns[:nav]
After I figured that out, my spec looked like this:
it "should get about us" do
get :about_us
assigns[:nav]
end
I want more though! I want rspec to assert whether or not it is equal to the string I set in the controller action which is: “about_us”
The first method I tried was:
assigns[:nav].should be(”about_us”)
I was sure that this would work, it made so much sense! But then, FAIL!!!
Why? Well, according to the rspec documentation, the method “be” returns true of false, not the object or the object value.
Given true, false, or nil, will pass if actual is true, false or nil (respectively). Given no args means the caller should satisfy an if condition (to be or not to be).
However, these could all be very good potentials:
assigns[:nav].should_not be_nil #Returns true because @nav is assigned
assigns[:nav].should be_an_instance_of(String) #Returns true because @nav evaluates to “about_us”, which is a string”
assigns[:nav].should_not be_empty #Returns true because @nav has a length of eight characters!
So, in my search for peace with this problem I found that “be” was not going to “be” my solution.
I needed something different, something that acted like “be” but returned the object value. My next guess was “equal.”
assigns[:nav].should equal(”about_us”)
To my dismay, this specification didn’t pass. It just waved it’s little middle finger right in my face. After consulting the documentation, it seems that the equal method really only passes if the expected object is the same as the one that it’s being matched again. IN MY FACE!
Passes if actual and expected are the same object (object identity).
So these could be valid:
assigns[:nav].should equal(assigns[:nav]) #Passes because @nav is being matched against itself
5.should equal(5) #Passes because 5 is really 5 no matter what.
@nav = assigns[:nav]; assigns[:nav].should equal(@nav); #Passes because @nav and assigns[:nav] both reference the same object!
And then, I saw it. The cute little method called “eql”. What was so different about “eql” than “equal”? It didn’t seem that there was a difference, that is, until I consulted THE DOCUMENTATION! This is what I wanted:
Passes if actual and expected are of equal value, but not necessarily the same object.
It seems that eql was the lucky charm I had been looking for all along. I went ahead and snapped in the code like so:
it "should get about us" do
get :about_us
assigns[:nav].should eql(”about_us”)
end
And to not so much my surprise, My First Test Passed!
Here is the stuff to remember:
equal: Matches Object to Object (@nav, @nav)
eql: Matches Object Value to Object (@nav,”about_us” )
be: Asserts truth or falsity of an obect (@nav, not nil)
Now I’m on to write more tests! Aren’t you supposed to take baby steps anyhow?