 |
January 2008 Archives
Hello Grails!
Posted by bleonard on January 30, 2008 at 06:37 PM | Permalink
| Comments (19)
NetBeans 6.1 M1 was just released, and with it comes rudimentary support for the Groovy language and the Grails framework. I say rudimentary because this is M1, but there's a lot of work in progress as you can see from this task list.
So, of course I'm anxious to compare Grails to Rails. What better way to do than by creating the same blog application I've been blogging about with Rails?
Setting Things Up
Unlike with Rails, the NetBeans Groovy plugin does not come bundled with Groovy and the Grails framework - these must be pre-installed on your system (don't worry, it's easy):
- Download and install Groovy
- Download and install Grails
- Download and install NetBeans 6.1 M1.
- Install the Groovy and Grails plugin (Tools > Plugins > Available Plugins)
- Open the NetBeans Options dialog and select the Groovy category. Set the Groovy and Grails home directories.
Creating the Grails Project
- Choose File > New Project to create a new Grails Application named GroovyWebLog. Your new Grails application will appear in the IDE:

Creating the Model
Or as Grails prefers to call them, Domain classes.
- Right-click the Domain classes node and select "Create new Domain Class":

- Name the class Post.
- When Post.groovy opens in the editor, add a single field, title:
class Post {
String title
}
Creating the Controller
- Right-click the Controllers node and select "Create new controller"
- Name the controller Blog.
- For now, we'll use dynamic scaffolding to create the application views at runtime. Replace the default contents of BlogController with the following:
class BlogController {
def scaffold = Post
}
Note, if our controller named matched the domain class name, we could then use def scaffolding = true. I kept the model and controller names different to match what we did with Rails.
Run the Application
- Right-click the GrailsWebLog project and select Grails > Run Application.
- If all goes well, NetBeans will start the Jetty server that comes bundled with Grails and launch your browser where you will see the Grails welcome page:

- Click the BlogController link:

- Create a New Post:

It's not immediately obvious, but the Id is a link which you can use to view the post details. From the detail page you can then edit and/or delete the post:

Adding Another Field
Our blog needs a body field.
- Edit Post.groovy and add a body field:
class Post {
String title
String body
}
- Return to the browser and depending on what you do, you may get an error. By default Grails is configured to drop and create the database every time a change is made, so if you tried to edit the existing record you were viewing, you got a NullPointerException. However, if you navigate back to the list, you will see that the body field has been detected and you can add a new record again:

A Friendlier Database Configuration
Surprisingly, we haven't had to talk about databases yet as the Grails framework magically took care of this for us. The Grails framework includes HSQLDB and all of the necessary configuration was setup for us in DataSource.groovy, which you'll find under the Configuration node:

You can also see from this configuration file that Grails supports the same three environments as Rails: development, test and production. It's also easy to switch to another database, just set the driver class name, jdbc url and copy the JDBC driver to the project's lib directory.
Do the following:
- Change the dbCreate property from "create-drop" to "update".
- Right-click the GrailsWebLog project and choose Grails > Stop Application.
- Richt-click the project again and choose Grails > Run Application.
- Now experiment with adding and/or deleting fields - you'll notice that the behavior is much more "Railsesque".
Validating Input
Like Rails, validation in Grails is very straightforward.
- Open Post.groovy and add the following constraints:
class Post {
String title
String body
static constraints = {
title(blank:false)
body(blank:false)
}
}
- Attempt to add a new Post without entering any data:

Customizing the View
Okay, enough with this dynamic scaffolding. Let's generate our controller and view code. Unfortunately, for this step I haven't found the menu option in NetBeans yet, so we'll resort to the command line for now.
- Open your command prompt and navigate to the GrailsWebLog project directory. If you've forgotten where this is, you can find it in the project's Properties dialog.
- Run the command grails generate-all Post:

- Now this created a new controller named PostController. I don't see a way to specify a controller name when using generate-all (or generate-controller). That's fine - I'll leave BlogController to do the dynamic scaffolding and use PostController for my customizations.
- Also created were a set of GSP (Groovy Server Pages) for managing the view for the PostController:

- Open list.gsp and delete everything from from the <h1>Post List<h1> to the </div> following the pagination buttons. In its place put the following:
<h1>The Groovy Blog</h1>
<g:each in="${postList}" var="post">
<h2>${post.title}</h2>
<p>${post.body}</p>
<small><g:link action="show" id="${post.id}">permalink</g:link></small>
<hr>
</g:each>
- Return to the browser and refresh the list page:

- To display the blog with the most recent entry first, add .reverse() to the end of postList in list.gsp:
<g:each in="${postList.reverse()}" var="post">

The Completed Application
GrailsWebLog.zip
Testing Rails Applications
Posted by bleonard on January 04, 2008 at 11:04 AM | Permalink
| Comments (0)
All well developed applications are supported by tests. In this entry I extend the web log I've been building to include some unit, functional and integration tests.
Setting Things Up
I'm going to begin from where I left off in my previous post: An Introduction to using AJAX with Rails: Take 2. Alternatively, you can start from RubyWeblogAJAX.zip, which is the completed project from that post.
Test the RubyWeblog Project
- Open the rubyweblog project.
- Note, if you are starting with the provided rubyweblog project, you will also need to create the rubyweblog_development database and run the migrations.
- Run the project and browse to http://localhost:3000/blog to verify that it works.
The Plan
We're going to look at the facilities Rails provides for testing our model classes, controller classes and entire application.
Model Testing (Unit Tests)
The Rails framework uses unit tests for testing of the model classes. Back when we first created the Post model class, a couple of test files were created for us, test/unit/post_test.rb and test/fixtures/post.yml:

The post.yml file contains test data that's made available to the unit test and reloaded in the database every time the test is run. Don't worry, this isn't going to affect your development database, but rather the test database that's configured in database.yml, which we haven't created yet:

Create the rubyweblog_test Database
- Switch to the Services window and expand the Databases node. We'll use an existing MySQL connection to create the test database. If you don't already have an existing MySQL database connection, create one for the development database.
- Expand the Drivers node, right-click the MySQL driver and choose Connect Using
- Set the Database URL to: jdbc:mysql://localhost/rubyweblog_development
- Set the User Name to: root
- Leave the Password blank
- Click OK to establish the connection
- Right-click an existing MySQL connection (connect first if not already) and select Execute Command.
- Enter create database rubyweblog_test
- Right-click the commend and select Run Statement
Prepare the Database
We need to run the migrations against the test database. This is done using the rake task db:test:prepare
- Right-click the rubyweblog project and choose Run Rake Task > db > test > prepare
Run the Default Unit Test
The default unit test that was created for us when the model was generated is very basic and really only servers to prove our test environment is properly configured.
- Open post_test.rb
- Right-click the file and select Run File.

If for some reason the test fails to run, the error messages are generally descriptive enough to alert you to the problem, like "Unknown database 'rubyweblog_test' if you forgot to create the test database first.
Test the Validations
The post model is pretty simple and doesn't offer a lot to test, but it does have a couple of validations when can test, so therefore, we can assert that an empty model is invalid:
def test_invalid_with_empty_attributes
post = Post.new
assert !post.valid? # An empty Post model will be invalid
assert post.errors.invalid?(:title) # The title field will have validation errors
assert post.errors.invalid?(:body) # The body field will have validation errors
end
Using Fixture Data
To give us something more to test, let's require blog titles be unique.
- Navigate to the tested class (Navigate > Go to Tested Class)
- Add
validates_uniqueness_of :title
- Open fixtures/post.yml and add the following:
first:
id: 1
title: George Jetson
body: Was a man ahead of his time
- Navigate back to the post_test.rb and add the following test method:
def test_unique_title
post = Post.new(:title => posts(:first).title, # Pull the title from the fixture
:body => "Whatever")
assert !post.save
assert_equal "has already been taken", post.errors.on(:title)
end
Run the Tests
There are several way to run the test:
- From the test file, right-click the file and choose Run File or Test File, as both do the same when executed from a test file.
- From the tested class, right-click the file and choose Test File.
Controller Testing (Functional Tests)
When the scaffolding was generated, Rails also generated a functional test stub in the test/functional directory, which has 8 tests for the actions created by the generator (index, list, show, new, create, edit, update, destroy).
- Open test/functional/blog_controller_test.rb.
- Right-click the file and choose Run File. You should see one failure:

This failure is caused by the validations we've added to the Post model as this line from the test_create method doesn't pass any arguments in with the post:
post :create, :post => {}
(Note, the first "post" in the line above refers to the HTTP Post method, while ":post" refers to the Post model).
- Add required parameters to the empty :post hash:
post :create, :post => { :title => "Astro",
:body => "Was loved by George" }
All 8 tests and 25 assertions should now pass.
Testing the post_comment Action
The default tests provide excellent examples on how to create tests for other controller actions. I'll create a new test for the additional controller action we've created since the controller was generated, post_comment:
def test_post_comment
xhr :post, # Simulate xml_http_request
:post_comment, # the action to call
{ :comment => { :comment => "What about Jane?" }}, # the parameters to post
nil, # session variables expected by the action
{ :post_id => 100 } # flash variables expected by the action
assert_response :success
assert_template '_comment'
assert_equal 'Comment was successfully added.', flash[:notice]
assert_equal 'What about Jane?', Comment.find_by_post_id(100).comment
end
Application Testing (Integration Tests)
Integration tests are used for testing application flow and generally test a scenario of events. The blog application is very simple, but we can still create a test scenario such as creating an entry, viewing the entry, editing the entry and adding a comment.
Integration tests are very much like functional tests, but since they can span multiple controllers you have to pass the controller as well as the action to the HTTP method (e.g., get "/blog/index"). Also, the Rails framework has not created a default integration test file for us, one must first be generated.
- Generate an Integration Test named ApplicationUsage.
- Add the following test method:
def test_creating_a_post
# Clear the database tables
Comment.delete_all
Post.delete_all
# Load the home page
get "/blog/index"
assert_response :success
assert_template "list"
# Load the New post page
get "/blog/new"
assert_response :success
assert_template "new"
# Create a new blog post
post "/blog/create", :post => { :title => "Integration Test Title",
:body => "Integration Test Body"}
assert_response :redirect
# Get the post variable from the controller so we can fetch the generated id
# which we'll use to get the record.
post_id = @controller.instance_variable_get(:@post).attributes['id']
# Show the newly created post
get "/blog/show/#{post_id}"
assert_response :success
assert_template "show"
# Edit the post
get "/blog/edit/#{post_id}"
assert_response :success
assert_template "edit"
# Post the edits
post "/blog/update/#{post_id}", :post => { :title => "Integration Test Title Updated",
:body => "Integration Test Body Updated"}
assert_response :redirect
# Verify the post exists
posts = Post.find(:all)
assert_equal 1, posts.size
# Confirm it's contents
post = posts[0]
assert_equal "Integration Test Title Updated", post.title
assert_equal "Integration Test Body Updated", post.body
end
- Run the file to execute the test.
You may have noticed that the test above does not test adding a comment. This is because I couldn't figure out how to set the flash from an integration test. Here's the signature for the xhr method I used from the functional test:
xhr(request_method, action, parameters = nil, session = nil, flash = nil)
and here's the signature for the xhr method for integration testing:
xhr(request_method, path, parameters = nil, headers = nil) And I just don't see a way to set the flash. If anyone knows, please let me know.
Running All Tests
You can run the entire suite of tests by selecting Run > Test "rubyweblog" or right-clicking the project and selecting Test. You'll also see a nice summary at the bottom of the editor window (this summary is there for every test run - it's just more useful in this case because it shows the aggregate of all test runs).

The Completed Application
RubyWebLogTested.zip
References
|