Annotate Models Modification
March 29th, 2007
annotate_models has been really useful for me. However when using fixture_groups fixtures in subfolders are ignored. I modified the plugin slightly to include them. With luck these changes can be merged with Dave Thomas ’s version.
Until then, here it is: annotate_models
./script/plugin install \
http://source.elevatorfight.com/public/annotate_models
Fixture Groups
March 29th, 2007
One of the things I like about working with Rails is test fixtures. However when the data model becomes more complex, the fixtures can become rather large. Worse yet, tests that require fixtures among two or more models feel clunky.
I wrote a plugin to help organize fixtures called fixture_groups.
./script/plugin install \
http://source.elevatorfight.com/public/fixture_groups
Example:
class BlahTest
fixture_group :group1
fixtures :foo, :bar
...
end
This will look in RAILS_ROOT/test/fixtures/group1 for the fixtures. If a fixture_group isn’t specified, then the fixtures will use the normal folder.
Update 8/10/07
For the most part, I’ve given up on fixtures in my tests. Although I have it in my mind to check out fixture scenarios soon.
Duplicate Test Names
March 24th, 2007
One of my biggest pet peeves of writing tests in ruby is based on something that makes ruby great. The openness of code.
...
def test_something
# some assertions
end
...
def test_something
# test with different assertions
end
...
Perhaps it’s my consistency towards test names or perhaps I’m focusing on the tree in the forest. But I’ve found myself in this problem more than a few times, editing the first test rather than the second, but the second essentially overrides the definition of the first.
In order to help detect this, I created a small rake task that searches through all tests, and checks the uniqueness of the test names within a test case.
It does ignore commented methods, however right now only accounts for # .
I may convert this into a plugin later, but until then save this in RAILS_ROOT/lib/tasks
> rake test:check_names
Everything looks good
> rake test:check_names
rake aborted
Multiple methods ["def test_something"] in test/unit/some_test.rb
(See full trace by running task with --trace)
While this keeps an eye out for me, I’m still lazy enough not to run it all the time. I decided to make it a core task for continuous integration, and then check it manually when I’m stumped why tests are not behaving as they should.
Active Record Test Helper
March 19th, 2007
When writing tests for Active Record Models I noticed a lot of textual clutter. I pulled out a small utility to help the assertions on validity: ArTestHelper (an ugly name, I know.)
Install as a Rails plugin:
./script/plugin install \
http://source.elevatorfight.com/public/ar_test_helper
When used in conjunction with Depth Merge. You can zip through validity testing.
...
include ElevatorUp::ArTestHelper
...
def test_missing_important_attributes
model = create_model_(:name => nil)
save_and_check_errors(model, :check_errors_on => :name)
model = create_model(:size => nil)
save_and_check_errors(model, :check_errors_on => :size)
model = create_model(:email => nil)
save_and_check_errors(model, :check_errors_on => :email)
end
def test_ugly_emails
model = create_model(:email => "")
save_and_check_errors(model, :check_errors_on => :email)
model = create_model(:email => "aaa")
save_and_check_errors(model, :check_errors_on => :email)
model = create_model(:email => "foo bar")
save_and_check_errors(model, :check_errors_on => :email)
model = create_model(:email => "foo@bar")
save_and_check_errors(model, :check_errors_on => :email)
end
Depth Merge
March 13th, 2007
Merge is rather useful, but it has the limitation of staying shallow. Here is a simple extension of an implemented depth merge, with one caveat. Passing in true to delete_nils will remove the key if the value is nil.
./script/plugin install http://source.elevatorfight.com/public/merge_extensions
To gut out the meat just grab this file
An example of use:
# Without trimming nils
hash1 = { :a => "foo", :b => { :c => "bar"} }
hash2 = { :b => { :c => "blah"} }
hash1.depth_merge(hash2) #=> { :a => "foo", :b => { :c => "blah"} }
# With trimming nils
hash1 = { :a => "foo", :b => { :c => "bar"} }
hash2 = { :b => nil }
hash1.depth_merge(hash2, true) #=> { :a => "foo" }
Again a very simple utility, however it comes in handy with testing.
# In Model
class Foo < ActiveRecord::Base
validates_presence_of :col1, :col2
end
# In Unit Test
...
def setup
@default_attributes = { :col1 => "foo", :col2 => "bar" }
end
def test_missing_important_fields
# A model with not only col1 == nil, but nil is never passed to the setter
model = create_model(:col1 => nil)
# do some checking on validity
model = create_model(:col2 => nil)
# again checking on validity
end
def test_something_else
model = create_model
end
private
def create_model(opts = {})
SomeModel.new(@default_attributes.depth_merge(opts, true))
end
...
Having a the depth part of the merge many not be handy in that scenario, but in functional tests they can help with composing the get/post
# In Functional Test
...
def setup
...
@default_params = {
:id => 5,
:foo => {
:col1 => "foo",
:col2 => "bar"
}
}
end
def test_something
post :some_action, params(:foo => { :col1 => nil })
...
end
def test_something_else
post :some_action, params
...
end
private
def params(opts = {})
@default_params.depth_merge(opts, true)
end
...
The premise for this is so tests become more concise, leaving only relevant information. Which in turn make the tests more readable.
Subdomain Assertions
March 8th, 2007
Working with subdomains with rails can be easy, especially with url_for_domain. However testing can be a pain.
assert_redirected_to helped when checking controller / action / parameters, but not asserting the subdomain. I rolled up a small assertion helper that can sit in test_helper.rb.
def assert_redirect_url(options = {})
opts = {:only_path => false, :controller => @controller.controller_name}.merge(options)
assert_equal url_for(opts), @response.redirect_url, "Error matching redirect url"
end
Example:
assert_redirect_url(:subdomain => "test-subdomain",
:controller => "test-controller", :action => "test-action")
Update 3/21/07
I recently found that assert_redirect_url collides with an existing rails test helper that is deprecated in Rails 1.2.2. By putting this function definition at the bottom of test_helper.rb it will be overridden. Of course you can always use an arbitrary name and avoid any conflicts.