h1

Jumping on the Rails Pt.5 – Veggie validations

July 23, 2009

So if you’ve been following along from the other parts of the series, you’d remember that we have been building a project story builder using cucumber and BDD. So far we have learnt how to use the process to flesh out functionality from the outside in and generate the basic functionality for our application, this part of the series will focus on saving our project and validating its data using the same process.

Although it may seem that we haven’t covered much ground in the last two parts, as we build up on our steps, the less we will have to do later. You’ll see what I mean shortly.

So lets move on to our next scenario, our projects needs to be able to save & have its data validated, we’ll start with the below scenario.


Scenario: When submitting the form the user must be alerted if the title is not present
  	Given an activated user logged in as 'reggie'
  	When I click new project
	And fill in the new project form without a title
	And submit the form
	Then the project will not be save
	And a validation message will be displayed

So we’ll add this snippet to our

projects.feature

So our first step to implement is filling in the form without a title, so lets get that step out the way.

registere_user_steps.rb

When /^fill in the new project form without a title$/ do
  fill_in 'project_description', :with => 'This project will help us manage stuff'
  fill_in 'project_aim', :with => 'To provide a service'
end

Strange, our test passed, why is that? Well if you remember from the last post, we didn’t implement the save functionality & we haven’t got any validation in place. Either way our tests are passing, so lets move on to the next.

When /^submit the form$/ do
  submit_form 'new_project'
end

Again our tests are passing but that ok, it’s what we expect, we have already implemented the submission process. So we can happily move on to the next step.


Then /^a flash the message will be displayed$/ do
  flash.should contain "A project must have a title"
end

Aha, our first failure, we haven’t implemented a validation message yet, so lets open up our project controller spec and create a few specs.

Here’s what we want:

  • It should save if it is valid
  • It should not save the project if it is not valid
  • It should display a validation error if no title is present

Here’s a rough outline of what we need to spec out


require File.dirname(__FILE__) + '/../spec_helper'

describe ProjectsController do
  it "should save if it is valid"
  it "should not save"
  it "should display a validation error"
end

If you notice there’s alot of repeation here, as we love being DRY, well restructure this a little

  • a valid project
    • should save if it is valid
  • an invalid project
    • should not save
    • It should display a validation error

Nice, now that reads better & we have a layout for our specs, lets see how this effects our specs layout.

describe ProjectsController do
	describe "POST create"
	  context "a valid project"
		it "should save"
	  end
	  context "an invalid project" do
	        it "should not save"
		it "should display a validation error"
	  end
	end
end

So our project controller spec now looks like the code above, as we can see, our specs are a lot more expressive in this fashion and allow others to quickly understand what a tests is supposed to do.

describe ProjectsController do
  describe "POST, create" do
    before(:each) do
      @project = mock_model(Project,
				:title=>"A project",
				:null_object=>true).as_new_record
      Project.stub!(:new).and_return @project
    end
    context "a valid project" do
      before(:each) do
        @project.stub!(:save).and_return true
        post :create
      end

      it "should save" do
	 @project.save.should eql true
     end
     it "should display a success flash message" do
      	flash.should contain "You have successfully created your new project"
     end
   end

   context "title is not present" do
    it "should not save the story"
   end

  end
end

For those that didn’t notice we’ve refactored our controller spec a little, firstly we’ve added a project mock and stubbed out its call to new. We’ve also added a spec to make sure that we can save our project, this passes automatically seeing as we implemented this code earlier via step definitions.

Now lets create our failing spec:

context "an invalid project" do
  before(:each) do
    @project.stub!(:title).and_return nil
    post :create
  end

  it "should not save the story" do
    @project.save.should eql false
  end

end

Here we basically make sure that we don’t get redirected to the projects info page, as it should not be save & we render the form again.

Now we have our condition to save our project, lets setup our validation we still need to get this passing, we need to add validation to our model, so lets open that and add the following:

validates_presence_of :title

Doing so makes our test pass, now on to our next step, we’ll come back to our spec in a sec.

Now we still have a few more steps to run through, these should be pretty simple though.

Then /^a validation message will be displayed$/ do
  response.should have_selector(:li, :content => "Title can't be blank")
end

To fix this we won’t bother with any spec’s, we’ll just add the following snippet to our new projects form:

<%= error_messages_for :project %>

All our scenario’s are now all passing and we can happily move on. Ok, now your probably wondering, hell what was all that effort for, we only setup validation for the title but we created crap loads of code.

It’s true, we setup quite a bit in the last post but in this one, we’ll see how much of a benefit that little bit of leg work was in a sec. Lets get a little ambitious and add to scenario to our projects.feature file.


Scenario: When submitting the form the user must be alerted if the description is not present
  	Given an activated user logged in as 'reggie'
	When I visit the home page
	And I click new project
	And fill in the new project form without a description
	And submit the form
	Then a validation message will be displayed say 'Description can't be blank'

Scenario: When submitting the form the user must be alerted if the aim is not present
  	Given an activated user logged in as 'reggie'
	When I visit the home page
	And I click new project
	And fill in the new project form without a aim
	And submit the form
	Then a validation message will be displayed say 'Aim can't be blank'

Running cucumber quickly we notice that we only have 5 steps to complete our scenario’s. Now if you remember we already created a step to cover validation of messages, wouldn’t it be nice if we could use that same step to cover our the other validation messages.

As we know we going to need this step in a second & our tests are running, lets do a little refactor our previous scenario so that it will cover the other validation messages as well. Change the last step to match the snippet below.

Then a validation message will be displayed say 'Title can't be blank'

Now we refactor its associated step to look like the following:

Then /^a validation message will be displayed say '(.*)'$/ do |message|
  response.should have_selector :li, :content => message
end

Here we’re telling cucumber to take the regular expression and pass it as the ‘message’, this nice little feature not only helps refactor our previous step, run cucumber again the other validation message steps will now cover too, how cool is that 😀

Using this method can save us a lot of time when it comes to writing scenario,s as well as helping us cover a lot ground quickly. Having said that take care when writting your steps, it’s not hard to find yourself lost, trying to work out why a step is not working. With that said, explicit names help to alleviate this no end.

Now with that said let’s move along.

When /^fill in the new project form without a description$/ do
  fill_in 'project_title', :with => 'new project'
  fill_in 'project_aim', :with => 'To provide a service'
end

As we have defined the step for submitting the button all the leg work is already done and we are greated by an error. We’ll we didnt get the validation message, so we’ll add this below snippet to our Project model.

validates_presence_of :description

We’re all passing again & we only have one more step to roll out, nice!

When /^fill in the new project form without a aim$/ do
  fill_in 'project_title', :with => 'new project'
  fill_in 'project_description', :with => 'This project will help us manage stuff'
end

Again we get the same error, so this time we added validation for our projects aim.

validates_presence_of :aim

We now have a fully functionality CRUD for our projects, we’ll look into making this more functional, adding scenarios to our project.

I’ve decided to put the code for this series on github partly to help myself remember what I’m learning here but also for others see the code in action & contribute to. I’d love input on the series and and suggestions on improvements as a whole.

Advertisements

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

%d bloggers like this: