Category Archives: Rspec

For Heaven’s Sake, At Least Test the CRUD

The very first integrated (feature) specs I setup it is to test the CRUD. If you don’t do anything else with feature specs, please, at least do these tests. You will be amazed at how much of your application is actually exercised and covered just with these simple tests.

Yes, you can and should test much more. And they don’t replace good unit and integrated tests.  But you will be surprised how many bugs these basic tests will catch. For example, my nemesis, the dreaded undefined method `blahblahblah' for nil:NilClass  in views.

These test will ensure the Adult model will:

  • Display all views (this alone is huge)
  • Data can be entered, displayed, updated, and destroyed (CRUD)
  • Model validations are respected
  • Potentially test model relations

I am going to show you how to test #index, #show, #edit, #update, #new, #create, and #destroy of a resource, an Adult model. I’ll break it down because the full spec file is long.

Here is the entire spec in it’s original project: adults_spec.rb

Setup

A little pre-knowledge would help; we are using Devise (for authentication), Rspec (for testing framework), Capybara (for integration tests). Note, we are not testing JavaScript in this test, and therefore invoke the RackTest as the Capybara driver for maximum speed.

Warden.test_mode!  gives us some nice Warden helper methods to use during testing. Notably the login_as(user, scope)  method. Warden is used under-the-hood by Devise.

seed_all_records  is just a method that will create a complete structure of records so that we have something to find and display. For example, it could create a user, company, orders, invoices, inventory, etc.

IMPORTANT: I am loading these records in a before(:all) do  block so that they are not recreated for every test. If  seed_all_records  creates a long and complex amount of records, as this real-life version does, it can dramatically speed up the test.

CAVEAT: If we need to create other new records, we need to manually keep track of them to delete them after use. See the #edit example.

For every test, the first thing we do is view the index,  visit unit_adults_path(@unit) . I like to start here and “click” the appropriate links to edit/show/delete tests.

#index

So we take a look at the index page, a table with a list of names (adults) and we check that we see some basic data (links and text).

 #show

We view the show page by clicking a link from the index page (Adult name). First, we make sure we are looking at the right show page. Then we click the “Return To List” link and make sure we go back to the index page. Finally, we try the “Edit” link of the Adult name and make sure were are taken to the edit form.

We look at the page.current_path  and test it to make sure we are on the right page. This may not work in your application as some paths may contain query values or other errata. But for simple specs with standard Rails routes, it works.

 #edit, #update

Like I noted above, we will need to create an Adult because we are going to change their data and we don’t want to affect the existing records. In an after do  block, we will delete this Adult.

We create this new Adult, then we make some changes in the edit form. But don’t submit yet! We’ll do that later.

In the first test, we submit the change, and make sure that any form changes we make are reflected on the Adult’s show page. Success! We can edit and submit Adult records. This tests a significant amount of the Adult model, validations, and potentially more (relations, counters, etc).

Lastly, we test that if the user cancels the edit, they are returned to the Adult show page and none of the entered changes are saved.

 #destroy

“I brought you into this world, I can take you out.”

Create a new Adult, then revisit the index page and click on the new Adult’s destroy link, and make sure they are gone and return to the index page. We also check that the flash notification is displayed.

Note: if you use a confirm: 'Are you sure?'  like Rails suggests as a default for destroy links, because we are using RackTest, it will not execute that JavaScript. Thus there is not confirmation dialog to click.

 #new, #update

Saved the longest for last. Also, the most important.

We are going to test two contexts: entering valid data, and entering invalid data.

Enter Valid Data

Simple, we click on the New Adult link, enter a bunch of data into the form, and save it. Then we verify that we are taken to the show page and can see all the data we entered.

This particular form has several select elements that allow the user to select from a list of options, as well as establish relations to other models. This is a good place to test this, but it could also be tested in #edit, #update. We verify that this Adult can have related Scouts, and no related Scouts. This also tests your models, validations, and relations. Good tests to have.

Enter Invalid Data

We want to see that when we enter invalid data, that model validations are respected, and that the record is not saved. When trying to submit invalid data, we return to the new form and check that the proper flash message is displayed.

In this example, I only test one field’s validation, that the Adult’s first_name can’t be blank. This is an excellent place to add more test for more validations.

 Conclusion

Put it all together, and you are testing a lot. I know they seem like simple tests, maybe too simple for some. But I think they are boilerplate for much more.

I said it before, but it bears repeating: setting up these basic CRUD integrated tests will catch a surprising amount of bugs.

Posted in Rails, Rspec. Tagged with , .

Create an In-memory Temporary ActiveRecord Table for Testing

I was reading Greg Niewisiewicz’s blog post on 6 Gems to Make Rails Development Easier and saw the first recommendation was for a gem called temping. Nice. But here is my take on the same thing without adding a gem (sort of) and doing it with in-memory SQLite tables.

I’m using Rspec3, so these example will need modification if you are using MiniTest.

Gemfile

Ok, so you will need to add the sqlite3 gem to your Gemfile, if you don’t already have it in there. Because I am only using SQLite for testing, I put it in the :test group.

Before(:all)

We need to create the table in SQLite via migration, then tell ActiveRecord to switch it’s database connection (temporarily) to use this in-memory db as the test environment database. We also add the ActiveRecord class so that we can, well, CRUD records.

After(:all)

We need to switch back to using your “test” database after all the tests are done in this spec. DON’T FORGET THIS STEP! Or all your other tests may fail, and you will be scratching your head why.

Good To Go

So now, you can operate on your temporary, in-memory, ActiveRecord table at lightning speed. And you don’t even need a gem. Just a few lines added to your test.

Caveat

Well, there is one downside, by using SQLite for the spec, you may not be using the database you would be running in production. This is true, unless you are using SQLite in production.

But, to be honest, you should try to be as database agnostic as possible. What if you have to switch from MySQL to PostgreSQL in the future for your production backend. Any MySQL database specific language you are using may fail in PostgreSQL.

On the plus side, the in-memory SQLite tables are really, really fast.

Posted in Rails, Rspec.