Project Ramon

A learning journey from a Ruby noob perspective

Lunch Panoply: Test-Driving a Data-Model

lunch_panoply2_header_img

Hello and happy Friday!

Today we’ll be covering a short refresher on how to put together an Rspec test for the data-model. If you missed yesterday’s post on setting up a test environment, you can take a look here.

Components of a Spec

There are 3 components that make up any good spec, they are the setup, the execution and a verification of desired results.

  1. The setup: Is where we establish the scenario that our individual spec test will cover
  2. The execution: Entails us creating a method call that triggers the spec call in our model to run
  3. The verification: Is where we make sure that what we expect to happen actually occurs from our test results

Here is a past post I wrote, covering my first attempts at learning to write good model tests.

Anatomy of a Data-Model Spec

Think of testing our data-models as a time to evaluate the building-blocks of our project application. I’ve been taught that we should be testing for behavior and not implementation. I stumbled upon this detailed StackOverflow post on the subject.

Now that we have a little theory to go on, lets take a look at how our specs should look like syntax-wise.

This is the basic structure of a spec_file. We require our spec_helper file and then define a describe block of the class we’re planning on adding specs inside of.

I found that it’s quicker for me to layout what I want to test for first, and only once the ‘what’ is defined, go into the implementation levels. Here’s an example from my current project lunch_panoply that demonstrates what I mean by separating out the ‘what’ (i.e. the blueprint) and the ‘how’ (i.e. the implementation details).

lunch_panoply2_img1

Above is a snippet (it contains most but not all of the specs for this model) of how I’m learning to approach building out a model spec in Rails.

Not taking the first spec into account on lines: 4-7, we can see that I’ve created a long list of pending specs. These pending specs are going to be the blue print I follow to cover the behaviors expected in the Venue class. Laying each of the individual specs in this way allows me to focus on one level of detail at a time, before any implementation code is addressed, I can now look over these pending tests and first ensure that I have the desired coverage handled.

If I ran this spec file with zeus, we can verify that there should be 1 passing and several pending specs:

lunch_panoply2_img2

Fantastic! 27 out of 28 specs are pending and the 0 failures you see in the above example means that our first spec is passing. I will run tests early and often, as doing so serves as a constant reminder of where I’m at in the process. Its also kind of neat to treat these similar to a check-box or to-do list. Watching one after the next spec pass, as we test-drive closer to app behavior coverage one model at a time.

Data-Model  Walk-thru

Now that we understand how to setup our model specs with a containing describe block, and have seen how I personally enjoy laying out pending specs first in order to ensure from my perspective that I’m adding the proper coverage, we can get started on actually doing a couple of examples… Red, Green, Re-factor style of course!

I’ve started out by creating a spec to ensure that my factory is in-fact valid. If you find that your specs used to run and pass with flying colors only to all fail after a brief stint away from your computer, there are two quick troubleshooting areas I’ve learned to be aware of.

Troubleshooting 

The first is to ensure that our test database is up to speed with our development database. What I mean by this is that as we migrate additions and subtractions to our data-model, the command rake db:migrate will make changes to our development database, but in order for those changes to be in tandem in our test-suite, we also will need to type the command rake db:test:prepare.

FactoryGirl and Faker in Action

If our test database is up to speed and your tests are all still unexpectedly failing, the second place I look is the factory of the spec_file(s) in question. Here’s the factory I’ve created for Venue:

lunch_panoply2_img3

First thing I wanted to point out is that we’re using require 'faker' at the top of the file so that we can generate some ‘sample-data’ for our class attributes. This not only makes our process a little less burdensome, it can be downright humorous at times to read some of this ‘sample-data’ automatically generated for us by our friend the Faker Gem.

The block that starts with FactoryGirl.define on line: 3 in the above example, is just a container to house the actual factory we are defining. Much in the same manner as we created a data-model block to house our individual specs earlier in this post.

Next up is to define the factory that will hold attribute data for our tests. factory :venue is how we actually define our factory, note that the v passed into our block isn’t necessary, and can be completely removed. It’s left in the examples because I’m researching a purpose for it, maybe it helps during association with other classes? I’m still working on understanding that.

Here is the example again in order to move ahead with our factory building walkthru:

lunch_panoply2_img3

Note that there are 3 lines where I removed the Faker Gem’s call to a method and instead statically coded in string values. This was due to a the :fax, :phone and :zip attributes needing to have explicitly defined lengths for test purposes. Testing behavior in this manner means that I just don’t want to expect the presence of data inside of these attributes, but also ensure that there is some standard validity to the behavior. In these cases, the size or length of the user data submitted for these attribute fields.

You can get a list of Faker method calls here. There are quite a bit of options available to satisfy our faker data-generation sweet tooth.

Time to Test-Drive

Let’s get started with implementing those pending specs in our venue_spec.rb file.

lunch_panoply2_img4

Just as a reminder, I like to think of it as sort of a score board, I’ve added the above illustration that demonstrates how many specs we need to implement.

Off to the races!

The context block you’ll see below, is there to keep our tests easy to read by making them more organized. In the following example, I’ve grouped specs with valid credentials together, as well as a set of specs that assert what invalid credentials would look like.

lunch_panoply2_img5

We can achieve DRYer specs using describe, context before and after.

DRYer Specs

  • Describe: Can be used to outline the general functionality of a class, is used for things
  • Context: Outlines a specific state by grouping related tests together (i.e. valid/invalid in my case)
  • Subject: Used for the thing we’re testing, specifies the thing to test
  • Before: Runs code before each spec, is used for actions
  • Let: Lazily runs code when it’s first used, and defines a named variable
  • After: Used when a spec requires post-example teardown
  • Since Rspec handles cleaning up the database by default, after isn’t used as frequently

Let’s get started on the first spec in the context of having valid credentials.

lunch_panoply2_img6

First I’m adding the familiar do end blocks so that I can add some implementation details inside. Next I’m creating a factory instance and assigning it to a local variable named venue. Note that I’m using some truncated syntax to create an instance of :venu through FactoryGirl. Thats one of many benefits I enjoy about the FactoryGirl gem, it was truly written with the developer in mind. If you’re not sure how to go from the full syntax of venue = FactoryGirl.create :venue to venue = create :venue here’s how I was able to do that.

lunch_panoply2_img7

Here’s an illustration of the spec_file I showed in yesterday’s post. The code we want to hone in on can be seen on line: 13 in the image above. Adding this will allow you to have an additional option of the truncated syntax venue = create :venue as well as allows you to fall back to the full syntax if you so desired venue = FactoryGirl.create :venue.

The :create method isn’t alone in FactoryGirl land, its a way to create but not persist an object in our test database. During those times we need to have a record or set of records persist, we can use the :build method in the exact fashion as :create.

Back to Spec Building

So we’ve created a test-object with a factory instance that we’ve defined, next is to make a call to the desired attribute.

lunch_panoply2_img8

We could have also overrode our :name attribute’s value by passing in a second argument in the FactoryGirl.create method like so:

lunch_panoply2_img9

I’ve only commented out line: 12 because I find leaving the attribute in question on its own line increases my readability at a glance. It’s just a matter of personal preference though, you can do whichever way works best for you.

The final step is to assert our desired behavior works. Here’s what that line of code looks like:

lunch_panoply2_img10

Now to run our specs to see what happens.

lunch_panoply2_img11

And Fail! Just what we expected, to be sure that this isn’t a typo somewhere, let’s look at our Venue model and see if we have any validations defined?

lunch_panoply2_img12

This is how test-driving an application is supposed to work. First we write the test, receive the fail, and then write just enough code in our model to make the spec pass. So let’s get too it.

lunch_panoply2_img13

Looking at line: 7, we have now added a validation for the presence of data for the :name attribute.

Let’s see if our spec is still failing:

lunch_panoply2_img14

Nice!

We’ve gone from 27 pending specs to 26, and have no failures. Lets take an opportunity to peak at what a spec looks like with invalid credentials.

Here’s what the spec in pending status looks like,

lunch_panoply2_img15

and here is the same spec with the implementation steps completed.

lunch_panoply2_img16

Now lets run our tests to see where we’re at:

lunch_panoply2_img17

And Yahtzee! We’ve gone from 26 to 25 pending specs with 0 failures.

As a fun little TGIF experiment, lets see how long it takes me to complete the venue_spec.

Starting the timer… Brought to us by Apimac Intuitive Apps.

lunch_panoply2_img18

And now I’m done!

Here’s the Rspec terminal output from my venue_spec file:

lunch_panoply2_img19

A look at my completed spec file:

And a snapshot of the time this took:

lunch_panoply2_img20

I hope that this post has given you a well-illustrated walk-thru of what it looks like to test-drive the data-model layer of a Rails application. If you have anything to add to this walkthrough, feel free to leave a comment.

Here is a AirPair from Edward Anderson, one of the many mentors that have been invaluable during this ongoing process of my efforts into becoming a confident Ruby and Rails developer. We’ll be covering a refactor of the model specs in a future post.

Have an enjoyable weekend!

And,

Stay tuned…

Categories: AirPair, Newbie, Ruby on rails

Tags: ,

4 replies

Trackbacks

  1. Lunch Panoply: Controller Testing | Project Ramon
  2. Getting Started with TDD in Rails -
  3. Rails Testing, Getting Started with TDD Best Practices

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s