Generating and Testing Behaviors

Posted by John W. Long on Wednesday, May 03, 2006 | |

Radiant ships with a custom generator for behaviors. Let’s have a look at it in action:


% script/generate behavior HelloWorld
      exists  app/behaviors/
      exists  test/unit/behaviors/
      create  app/behaviors/hello_world_behavior.rb
      create  test/unit/behaviors/hello_world_behavior_test.rb

Open hello_world_behavior.rb. You will see that the generator has created a nice skeleton for your new behavior:


class HelloWorldBehavior < Behavior::Base
  
  register "Hello World"
  
  description %{
    Describe Hello World behavior here.
  }
  
end

As noted in the previous article about behaviors, the first line in the behavior registers the behavior under the “Hello World” name. This means that it will now show up in the behavior combo box on the edit page screen. The description slot is a place for you to describe what the behavior does. Eventually, you will be able to access these descriptions from the interface, but for now they only show up in code.

Now open up hello_world_behavior_test.rb:


class HelloWorldBehaviorTest < Test::Unit::TestCase
  test_helper :behavior_render

  def setup
    @page = Page.new(:title => 'Test Page', :slug => "\\")
    @page.behavior_id = 'Hello World'
    @behavior = @page.behavior
  end

  # Replace this with your real tests.
  def test_title_tag
    assert_renders 'Test Page', '<r:title />'
  end
end

The generator has created already created a nice test case for you. Replace the test_title_tag method with the following code:


def test_hello_tag
  assert_renders 'Hello World!', '<r:hello />'
end

Now run your unit test:


% ruby test/unit/behaviors/hello_world_behavior.rb
Loaded suite test/unit/behaviors/hello_world_behavior_test
Started
F
Finished in 0.240644 seconds.

  1) Failure:
test_hello_tag(HelloWorldBehaviorTest)
    [/Users/jlong/Workspaces/radiant/trunk/radiant/test/helpers/behavior_render_test_helper.rb:5:in `assert_renders'
     test/unit/behaviors/hello_world_behavior_test.rb:13:in `test_hello_tag']:
<"Hello World!"> expected but was <"<div><strong>undefined tag `hello'</strong></div>">

1 tests, 1 assertions, 1 failures, 0 errors

Whoops! Our first failure. This is actually just what we want because we are doing test first development. As you can see the test case is complaining because we haven’t defined the hello tag. Let’s do that now. Open up hello_world_behavior.rb again. Add the following block to the HelloWorldBehavior class underneath the description:


define_tags do
  tag 'hello' do
    'Hello World!'
  end
end

Now run the unit tests again:


% ruby test/unit/behaviors/hello_world_behavior_test.rb 
Loaded suite test/unit/behaviors/hello_world_behavior_test
Started
.
Finished in 0.161996 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Wow. Look at that! They passed on the first try!

Let’s make the hello tag a little more robust. I would like to be able to specify the name of the person in the tag. First, we should update the unit test. Add the following code to the test case:


def test_hello_tag_with_name_attribute
  assert_renders 'Hello John!', '<r:hello name="John" />'
end

And watch it run:


% ruby test/unit/behaviors/hello_world_behavior_test.rb 
Loaded suite test/unit/behaviors/hello_world_behavior_test
Started
.F
Finished in 0.218689 seconds.

  1) Failure:
test_hello_tag_with_name_attribute(HelloWorldBehaviorTest)
    [/Users/jlong/Workspaces/radiant/trunk/radiant/test/helpers/behavior_render_test_helper.rb:5:in `assert_renders'
     test/unit/behaviors/hello_world_behavior_test.rb:17:in `test_hello_tag_with_name_attribute']:
<"Hello John!"> expected but was <"Hello World!">

2 tests, 2 assertions, 1 failures, 0 errors

Beautiful! Another failure! Test::Unit is complaining because the assert_renders assertion expects “Hello John!”, but instead it got “Hello World!”. Let’s fix that now. Open up hello_world_behavior again and replace the hello tag with the following code:


tag 'hello' do |tag|
  name = tag.attr['name'] || 'World'
  "Hello #{name}!" 
end

And run your tests:


% ruby test/unit/behaviors/hello_world_behavior_test.rb 
Loaded suite test/unit/behaviors/hello_world_behavior_test
Started
..
Finished in 0.197866 seconds.

2 tests, 2 assertions, 0 failures, 0 errors

Whew! Tests pass. This means that we’ve succeeded in creating a behavior with a hello tag which has a nice attribute called name in which we can specify the name of the person that we want to say hello to. You may want to fire up Radiant now and test it out.

If you create an interesting behavior that you would like to share with others, please announce it on the mailing list and add it to the third-party behaviors page. Unit tested behaviors may be eligible for inclusion in the core.