If you’ve been keeping up with my recent posts, you’re aware that I’ve been test-driving my latest AirPair project, lunch_panoply. Today we’ll be going over a refactor of the model_specs.
Drying up Our Specs
The first thing I look for when refactoring is redundancy. For me, its the lowest-hanging fruit out of a basket full of additional approaches to cleaning up code smells.
Below is an illustration of a code sample from the
If we take a look at the first line underneath each of our
it blocks, its hard to miss all of those identical factory instantiations, lets see how we can eliminate this unnecessary redundancy from this spec_file.
Rspec allows us to use two memoized helper methods
let! in order to have some benefits in our tests such as lazy-loading factory objects. Here is a link to an insightful StackOverflow post that goes into greater detail. And here is a link to a post that displays a good example.
Finally, this is how
let essentially works:
Using the Rspec helper method
let, we have reduced our code to the following:
Admittedly, I was hoping for a complete removal of having to call the
company object in each spec. But this isn’t a terrible start, a half-step in the right direction is better than being stuck at square one.
Lets look at another code snippet from the same file, continuing our first approach of simply reducing or eliminating duplicate code smells from the file:
Here we’re setting up more than on instance of
company in order to store it inside of an array that will represent an instance variable with the same name
companies that holds all instances of the class.
let again, allows us to remove each of the identical array assignments in the spec file from the example above.
The code now looks a little less redundant in the sense that we only are defining the
companies array one time. Here’s a snapshot of this minor improvement:
So now I have two calls to the
let helper method, one for the array
companies and the other is to create a
company factory object to use throughout the entire spec.
I could add additional
let methods that would
build the various
company3 factory objects, but personally, I find leaving them in as-is is not only easier to read, but prevents me from having to scroll up the entire file in order to see which object’s attributes I’d need for a particular spec.
I remember a previous mentor session with Mark Simoneau about using shoulda-matchers to tidy up some unnecessarily loquacious specs. I like to use these when testing for specs that tests for the presence of attributes we’ve created presence validations for in the model. Lets take a look at a snippet of some of those specs.
The first thing I’d like to address is my less than perfect description strings that describe each of the above specs. The
it blocks take a string strictly for humans to read in order to make quick sense of what each specific block of coverage is asserting. I think I can do slightly better at making these descriptive sentences easier to read at a glance.
Addressing the second code snippet from the above illustrations, I’ve changed the text to read as:
I remember Edward Anderson, sharing with me that there is no need to spare verboseness in the description text, for the exact reasons I’ve mentioned above. So this example is now larger in character size, but for the tradeoff of being arguably easier to read at a glance for any future developers looking to understand this particular spec’s purpose.
The same goes for the refactored example above. It sounds kind of unfamiliar to me to consider changing text inside of a spec_file a refactor, but since I’m changing the structure of the specs without changing any behavior, I need to embrace the fact that technically this is in fact fitting of the definition of a refactor.
Now that we have that tackled, lets get to using our concise Shoulda-Matchers.
Here are a few links I find useful when attempting to refactor specs using the shoulda-matchers gem by thoughtbot:
And here is a snapshot of my company_spec file once I’ve refactored by swapping tests with shoulda-matchers. I’ve kept the old specs up for the city and state attributes just to demonstrate the concise power of using shoulda-matchers. I’ll be removing these before my Github commit.
And there we have it! A refactor example of a model being covered by Rspec.
I am still learning so much about TDD, so if you have anything to add, especially in what I could further refactor from the code samples above feel free to comment.
In my next post, I’ll be covering how I refactor a controller spec.
Categories: Ruby on rails