Scenes - a Rails plugin

We're big fans of Cucumber at work - we're using it on all new projects we start, and it's quickly becoming as essential to us as writing tests using Rspec. We first started using it last year on a reasonably complicated Rails app, and we had a lot of features which required the system to be in a certain state before we could test what the feature was actually about. There are different ways to do this now - e.g. background steps - but as a solution to this problem I wrote what eventually became scenes.

It's probably easiest to demonstrate with a simple example.

Scenes::Character.named("David") {
  User.create(:name => "David")
}

Scenes::Character.named("Joe") {
  User.create(:name => "Joe")
}

Scenes::Scene.named("David and Joe") {
  Scenes::Character["David"]
  Scenes::Character["Joe"]
}

This will set up a scene containing two characters - David and Joe. In the Rails console, we can now load this scene and then play it back to create these users.

Loading development environment (Rails 2.3.2)
>Scenes::load
=> ["scenes/scenes.rb"]
>Scenes::Scene.list
=> ["David and Joe"]

Scenes::load will read all ruby files in the scenes/ directory. Scenes::Scene.list lists the scenes that have been loaded.

>User.count
=> 0
>Scenes::Scene["David and Joe"].play
=> true
>User.all.map(&:name)
=> ["David", "Joe"]

Playing this scene back created David and Joe. The first time a character is referenced, the object is created in the database. Subsequent references will load this object rather than duplicating it. Characters can contain any additional code for setting up the character (eg, activating a user account), but must return the object they are creating.

Scenes::Character.named("David") {
  u = User.create(:name => "David")
  u.activate!
  u
}

Usage with Cucumber

To play scenes in a cucumber scenario, you first have to load the scenes, and then create a step which will load them.

Scenes::load

Given /^the scene "(.+)"$/i do |scene_name|
  Scenes::Scene[scene_name].play
end

I put this code in my features/support/env.rb, although the step definition should probably live in its own definition file. Once this code is in place you can use a scene in a scenario as follows

Given the scene "David and Joe"
When I am on the users page
I should see "2" users

As mentioned at the beginning of this post, this is a very simple example, but it should show how to use scenes.

Rake tasks

There are also two rake tasks for scenes, the first will list all the scenes you have set up and allow you to load them in to your development environment.

$ rake scenes
(in /Users/barry/code/ruby/example)

Available Scenes
----------------

   1 - David and Joe

This will REBUILD the database first

Or 0/q to quit
> 1
==  CreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0019s
==  CreateUsers: migrated (0.0027s) =======================

This task will run rake db:migrate:reset to clear your development database, then play the selected scene. This is handy for checking that you have set your scene up correctly, and it's been a useful way of setting apps up in a predetermined state for weekly demos. The other task allows you to save your current development environment as a scene for future playback.

$ rake scenes:save
(in /Users/barry/code/ruby/example)

Enter a name for this scene:
> my awesome scene
Saved
$ ls scenes/saved/
my_awesome_scene.rb	my_awesome_scene.yml

This saves your data in a yaml file along with a ruby file which sets the scene. This task is quite simple, and if you have any database constraints in place it probably won't work as expected.

Hopefully, that's given a basic example of using this plugin. It's still a work in progress, and the code is up on github.


Tags : cucumber, programming, rails, ruby, scenes

blog comments powered by Disqus