Took a little time today to give the site a makeover, and fix some small bugs. I still don't claim to have any eye for aesthetics, but I think this probably looks a lot nicer than before. Clean & simple.

I also released my first public Rails plugin this morning (with the wildly clever name of RestfulCrudIntegrationTester), a whole 36 hours sooner than I thought I would yesterday.

I've just finally started delving into Integration Testing (yah, I know, I'm a little late to the party.) I was writing tests for two different projects (one at home and one at work) and noticed even though they were very different projects, I was duplicating a lot of low level integration test code. So... I extracted it out into a plugin.

Now, on both projects, and any others I use the plugin in, I can just say things like...
new_session_as('jon','Exc3l1ent_p@s5w0rd!') do |jon|
  jon.updates_article(1,{:article => {:subject => 'New Subject'}})
end
And then the Plugin will go try to login as that user (using the sessions_controller), and exercise both the edit and update actions in the articles_controller, as well as confirm that the edit form has the correct action, method, and input elements for a RESTful update.

Note, that the plugin is only for very RESTful controllers (if you didn't get that already), and it makes a few big assumptions on how your Rails app works. I tried to make sure the assumptions followed Rails conventions as much as possible.

Some of the initial code came from Jamis Buck's post on the subject from over a year ago, (yah, yah, late to the party) so thanks to Jamis for getting me started on the right path.

Strangly, as long as Integration Testing has been around, I didn't find any existing plugins to provide this kind of basic framework. So, I'm hoping I didn't waste time reinventing the wheel, and instead have found an unfilled need and provided a worthwhile contribution to the Rails community. Time will tell on that.

Here's the complete README file from the 0.1 version of plugin.

RestfulCrudIntegrationTester
============================
Provides a framework of common integration
tests for RESTful CRUD interactions.

How To Use
==========
class ArticleTest < ActionController::IntegrationTest
  include RestfulCrudIntegrationTester
  
  def test_some_article_functionality
  	new_session_as('jonnyg','testing123') do |jon|
      params = {
      	:article => {
      		:title => 'Foo Bites Bar',
      		:content => 'Bar was bitten by Foo yesterday.' 
      	}
      }
      jon.creates_story(params)
      params = {:article => {:title => 'Bar Bitten Badly'}}
      jon.updates_story(1,params)
      jon.reads_story(1)
      jon.deletes_story(1)
    end
  end
end

Assumptions
===========
The plugin makes certain assumptions about your application.
Some of these can be bypassed or overridden if your app does
not conform.

* you have appropriate map.resources lines in your routes.rb
	for any controllers you intend to test with these methods.
* sessions_path helper method returns the path to a controller
	that controls user logins. (Provided automatically by
	Rails if you have a sessions_controller and routes.rb
	includes "map.resources :sessions".)
	@ Override by adding your own sessions_path method to
	application_helper
	
* your sessions controller accepts parameters in the form of...
	{:user => {:username => 'xxx', :password => 'yyy'}}
	@ Override by providing your own new_session_as method
		that generates an appropriate session for your app
		with the user provided.

Provided Methods
================
-Create Sessions-
-----------------
new_session:
	creates generic session (i.e. user not logged into your site).
	
	#example
	new_session do |guest|
		#guest.does_things here
	end
	
new_session_as:
	creates session as user with provided username and password.
	
	***assumes that you have a 'sessions_controller' and that it
	takes params in the form of... 
	{:user => {:username => 'xxx', :password => 'yyy'}}
	
-Do CRUD-
---------
All CRUD tasks can be passed a block to do additional assertions
sess.reads_():
	performs a GET to _path()
	asserts a :success response
	yields if you passed a block containing more assertions
	
sess.creates_():
	performs a GET to new__path
	asserts a :success response
	asserts page contains a form with a _path action
		and a 'post' method.
	asserts form contains appropriately named input elements
		for each of the  you provided.
		i.e. 'person[first_name]'
	performs a POST to _path passing 
	yields if you passed a block containing more assertions
	if you did NOT pass a block
		asserts a :redirect response
		follows redirect
		asserts a :success response
	
	
sess.updates_(,)
	performs a GET to edit__path()
	asserts a :success response
	asserts page contains a form with a _path action
		and a 'post' method.
        asserts form contains a hidden input field named '_method'
    	        and a value of 'put'.
	asserts form contains appropriately named input elements
		for each of the  you provided.
		i.e. 'person[first_name]'
	performs a PUT to _path passing 
	yields if you passed a block containing more assertions
	if you did NOT pass a block
		asserts a :redirect response
		follows redirect
		asserts a :success response
		
sess.deletes_():
	performs a DELETE to _path()
	yields if you passed a block containing more assertions
	if you did NOT pass a block
		asserts a :redirect response
		follows redirect
		asserts a :success response
Comments: [add comment]