Wednesday, 24 March 2010

Rails - Day 10 - Testing Rails Controller

Rails  - Day 1 - The RubyGem Love Story
Rails -  Day 10 - Testing Rails Controllers
Rails -  Day 13 -ActiveRecord Relationships Part II
Rails - Day 15 - Rails Forms Part II

In the past post, I talked a little about rendering content.

In this post, I want to touch lightly on testing with respect to rails of course.  I am going to start with Controller testing or as it is known in rails, functional testing.  

If you are one of my ten or so readership then it is likely that you are a .NET developer.  If you are somebody who aligns themselves with those super cool, pola neck wearing ALT.NET guys, then you have quite probably written a blog post along the lines of If you are not practicising TDD, then you should have your arms and legs cut off.

So with this frightening threat on our limbs made, we better ensure we are following the TDD mantra by writing test code before application code.

I also want to introduce a sample application that I am going to use to illustrate the concepts.  I run my own business and keep a record of all my expenses in a google docs spreadsheet.  I have often toyed with the idea of writing something to record these entries and this seems as good as time as any to create such an application.

I have created a project which is named rather predictably expensetracker.

When I am developing, I like to create the user interface as a first iteration.  The code is basically stubbed out as I create the HTML skeleton of the site.  This allows me to get feedback from the client after we have agreed on the wireframes and also before we have written any serious server side code.  I then use the UI to drive the model of my application.  This might seem like heresy to the DDD zealots of which there are many but I find this a much better medium for feedback than any user story that can be wriitten.

This skeleton of the site does have some server code, and I like to make sure the navigation of the code is running through the web framework I am using.  

For the expensetracker application, I will obviously need a page to display a list of the expenses I have recorded thus far.  Below is my mock up of the page that will list all my expenses.  This is just plain HTML at this stage but we want to at least have this rendered from a Rails controller action and the HTML generated from a combination of HAML and SASS.

Using my amazing powers of deduction and having read and been particularly underwhelmed by that blue book that makes some devs go weak at the knees, I think an expense resource will be required at some stage.

With that said, I steadfastly progress further and generate an expense resource with the ruby script/generate resource Expense command which generates the following files for us:

As I mentioned in this previous post, the index action of the resource's controller is generally used to display all or a subset of the resource in question.

So if I am being righteous to the God of TDD, I should write the test for the index action before I write the controller action.  I also like to have some test cases in place to set an example for other developers working on the project.

Testing Rails Controller Testing a.k.a. Functional Testing

In rails writing tests that test the actions of a single controller is called writing functional tests for that particular controller. You can see below that the resource generator has created a stubbed out test file for us in test/functional/expenses_controller_test.rb.

Functional tests interact with actions in the Rails controllers.  They can test what variables each action prepares for the view, can test errors that Rails might raise and test the HTML that would get rendered with the view.

We should test for such things as:

  • Was the web request successful?
  • Was the user redirected to the correct page?
  • Was the user correctly authenticated?
  • Was the correct object stored in the response template?
  • Was the appropriate message displayed to the user in the view?

Before I go any further, it should be noted that I am going to use the default test runner and not something like rspec.  I prefer the simplicity of the default test runner and I do not have much need for the extra fluff that comes with rspec or some of the other more wordy clones.

So at this minute in time, all I want to do is test that I can get a success response and that the correct view template is selected from the index action of the ExpensesController.  

Below is a test that does just that:

The above method simulates a request on the index action of the ExpensesController making sure that the request was successful and also that the correct template file is in place.

The get method kicks off a web request and populates the response.  In our example we are just passing the name of the action as a symbol but there are 3 optional parameters we could use, for example if we were testing the show action, we could pass in an optional hash of request parameters into the action (e.g. query string parameters or post variables).  An example of such a call would be:

get(:show, {'id' => "12", {'user_id' => 1})

Just as there is a get method,  there are similar methods for the other HTTP verbs, post, put, head and delete.

So now we have written our first test, how do we test it?  It is time for one of the main heroes of our piece to make a reappearance.  I speak of rake.  Many of the rails workflow commands are executed via rake and it is not just a simple build engine DSL which was my original impression.  If we want to see what test commands are available through rake, we can simply type rake -T test, which will present us with the following:

We can see from the above list, that there is a rake test:functionals command that will suit our needs.  

Bearing in mind that we have neither created an action called index or created a template named index.html.haml, we would be in fairly big trouble if the test passed.  

If we execute the rake test:functionals, we get the following message:

Here you can see, that the test does indeed fail and we are also told ActionController::UnknownAction: No action responded to index.

If we now add the folllowing action to our ExpensesController like this:

We can rerun the tests with the same rake command and get the following response:

We can see that our test is failing because: ActionController::UnknownAction: No action responded to index.

We can now add the template to the required destination of app/views/expenses.

We now cross our fingers and rerun the test:

As we can see from the above, the test has ran and our 2 assertions have rightly passed.

Now we have the index rendering, we add the haml and sass for our UI mock up.  

Below is my badly designed index page that will display all my expenses that is now being rendered from the index action.  It should be noted that I am not rendering any content from the database.........yet.

If this was a work scenario, I would now go back to the client to check my assumptions before writing any more server side code.

The New Action

We will also need a page to record our expenses and as I mentioned in this post, we use the new action to display a form for creating a new resource.  In our example, the url will be /expenses/new/.

Again, as we are doing this test first, we create the following test:

We then add a blank new method to the ExpensesControler and a new view template at app/views/expenses/new.html.haml and run the test, we should be informed that all is good.

In this post, we have touched on controller testing.

In the next post, I want to touch on Model testing.

No comments:

Post a Comment