Saturday, September 30, 2006
Rails Model View Controller + Presenter?
Ruby on Rails directs you to use Model View Controller by convention. This often results in a one to many relationship between Controllers and Views. A common controller could contain the following code.
class StandardsController < ApplicationControllerThis controller implementation works fine; however, the results method can become a bear to test. To solve this issue my team began inserting another layer: a Presenter. The main responsibility of a Presenter is to expose data for the view to consume. After introducing the presenter the controller becomes much slimmer.
def list
@standards = Standard.find(:all)
end
def results
standards = Standard.find(:all)
@total_standards = standards.size
@standards_for_hr = standards.select { |standard| standard.department == 'hr }
@standard_categories = standards.collect { |standard| standard.category }.uniq
...
end
end
class StandardsController < ApplicationControllerThe Standard::ResultsPresenter class handles aggregating all the required data.
def list
@standards = Standard.find(:all)
end
def results
@presenter = Standard::ResultsPresenter.new()
end
end
class Standard::ResultsPresenterAfter introducing this abstraction the Presenter can be tested in isolation.
def total_standards
standards.size
end
def standards_for_hr
standards.select { |standard| standard.department == 'hr }
end
def standard_categories
standards.collect { |standard| standard.category }.uniq
end
def standards
Standard.find(:all)
end
end
class Standard::ResultsPresenterTest < Test::Unit::TestCaseWe like this style because it's much cleaner than the previously required code that lived in the controller tests. However, there is overhead involved in generating this additional layer. Because of the overhead we generally don't add a presenter until we notice that testing has become painful in the controller test file.
def test_total_standards
Standard.expects(:find).with(:all).returns([1,2,3])
assert_equal 3, Standard::ResultsPresenter.total_standards
end
def test_standards_for_hr
standard_stubs = [stub(:department=>'hr'), stub(:department=>'other')]
Standard.expects(:find).with(:all).returns(standard_stubs)
assert_equal 1, Standard::ResultsPresenter.standards_for_hr.size
end
def test_standard_categories
standard_stubs = [stub(:catagory=>'Ruby'), stub(:catagor=>'Ruby')]
Standard.expects(:find).with(:all).returns(standard_stubs)
assert_equal ['Ruby'], Standard::ResultsPresenter.standard_categories
end
end
Friday, September 29, 2006
Remove Subversion from a tree
The following code will remove all the .svn folders from a tree (starting at the current file's directory).
When did I use this? Every time I start a new project I check it into a local subversion repository. After working on the code for a bit, if I decide that it's a project worth distributing I register it somewhere else (such as RubyForge). If my project is accepted, I'll transfer the code to the projects repository. The easiest way, I've found, to move the code is to remove the local .svn directories and check out version 0 of the new repository into the project's root. At this point, I can svn add everything and check in.
I'm sure there's a better way, but this is simple and it works.
Find.find(File.dirname(__FILE__)) { |path| `rm -rf #{path}` if path =~ /\.svn$/}I've needed this enough times that I thought it might save someone else some time.When did I use this? Every time I start a new project I check it into a local subversion repository. After working on the code for a bit, if I decide that it's a project worth distributing I register it somewhere else (such as RubyForge). If my project is accepted, I'll transfer the code to the projects repository. The easiest way, I've found, to move the code is to remove the local .svn directories and check out version 0 of the new repository into the project's root. At this point, I can svn add everything and check in.
I'm sure there's a better way, but this is simple and it works.
Tuesday, September 26, 2006
Test::Unit test creation
Creating a unit test in Ruby is very similar to Java: create a method that begins with
This began a discussion on what a superior approach to writing tests could be when using Ruby. We implemented several examples before deciding on our preference.
However, moving to this new style of test definition can cause issues. The first noticeable issue was that TextMate would no longer run individual tests. We quickly fixed this issue by looking at the code in the Ruby Bundle. The fix was to change the regex that selects the method you are testing. The code below shows how you can capture either the previous call to the test class method or the previously defined test method.
test_. In a recent discussion with some colleagues, Zak Tamsen and Muness Alrubaie, Zak described his distaste for this common convention. He continued by pointing out that using .NET Attributes was a superior approach for identifying tests.This began a discussion on what a superior approach to writing tests could be when using Ruby. We implemented several examples before deciding on our preference.
testEach implementation contained limitations. In the end we chose to go with a very simple implementation that is similar to how RSpec defines specifications.
def add_returns_the_sum_of_two_numbers
assert_equal 4, add(2, 2)
end
test 'add returns the sum of two numbers'
assert_equal 4 do
add(2,2)
end
test 'add returns the sum of two numbers' doTo accommodate this syntax we added the
assert_equal 4, add(2, 2)
end
test class method to Test::Unit::TestCase.class << Test::Unit::TestCaseAn additional benefit we were able to include in our change was the ability to raise an error when a test was defined with a duplicate name (or description in our case).
def test(name, &block)
test_name = :"test_#{name.gsub(' ','_')}"
raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name.to_s
define_method test_name, &block
end
end
However, moving to this new style of test definition can cause issues. The first noticeable issue was that TextMate would no longer run individual tests. We quickly fixed this issue by looking at the code in the Ruby Bundle. The fix was to change the regex that selects the method you are testing. The code below shows how you can capture either the previous call to the test class method or the previously defined test method.
File.open(ENV['TM_FILEPATH']) do |f|We also created a TextMate snippet in the Ruby Bundle to help us create tests in our new style. The following code is the snippet for easily creating tests.
f.read.split("\n")[0...n].reverse.each do |line|
if line =~ /^\s*test\s+"([_a-z][_a-z0-9 ]*[\?!]?)"\s+do\s*$/i
print "test_#{$1.gsub(' ', '_')}"
break
elsif line =~ /^\s*def ([_a-z][_a-z0-9]*[\?!]?)/i
print $1
break
end
end
end
test "${1:test name}" do
$0
endAfter these quick changes we are quite happy working with our new format for creating tests.Labels: RailsConf2007
Thursday, September 21, 2006
Ruby Stub Variations: Stubba
Ruby Stub Variations: Introduction
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
In my last entry I described how, using Struct, you can create stubs without creating your own stub implementations. Struct also provides you the power of creating and keeping reference to a class. But, on many occasions you don't need the extra capability. On these occasions the unnecessary flexibility requires you to enter additional code. There is another alternative that allows you to initialize a class similarly to OpenStruct: Stubba.
Stubba is a stubbing framework that provides great flexibility. The example test can be implemented using Stubba with the following code.
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
In my last entry I described how, using Struct, you can create stubs without creating your own stub implementations. Struct also provides you the power of creating and keeping reference to a class. But, on many occasions you don't need the extra capability. On these occasions the unnecessary flexibility requires you to enter additional code. There is another alternative that allows you to initialize a class similarly to OpenStruct: Stubba.
Stubba is a stubbing framework that provides great flexibility. The example test can be implemented using Stubba with the following code.
def test_values_are_appened_to_insert_statementStubba provides the same simplicity of OpenStruct and addresses the limitations. Stubba correctly responds to predefined methods and even returns as expected from
statement = Insert.into[:table_name].values do
stub(:to_sql=>'select column1, column2 from table2')
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
respond_to?. However, the major benefit to using Stubba is the ability to temporarily change behavior of existing objects. For example, if I chose to use the Select class, but wanted to stub out the to_sql method I would use the following code.def test_values_are_appened_to_insert_statementStubba is a great alternative to the previously mentioned stub alternatives. In the end, which stub you choose should be based on your needs of your project.
Select.any_instance.stubs(:to_sql).returns('select column1, column2 from table2')
statement = Insert.into[:table_name].values do
Select[:column1, :column2].from[:table2]
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Tuesday, September 19, 2006
Ruby Form Template Method Using Extend
In Martin Fowler's book, Refactoring, he describes how you can form a template method to eliminate duplicate behavior. I wont get into the motivations for doing such a thing; for that, I suggest buying the book. However, I would like to use the example to show how I would implement it using Ruby.
The prefactored code in Ruby could look like this:
For example, let's imagine that the next requirement of our application is to display the above information for only the previous month. The current statement class gives a list of each rental associated with a customer for all months. To satisfy our new requirement we could create a MonthlyStatement class similar to the code below.
The prefactored code in Ruby could look like this:
class CustomerThe first refactoring step is to create a Statement base class and two derived classes that inherit from Statement. However, we will need a Statement class and two modules that contain the methods we require.
def statement
result = "Rental Record for #{name}\n"
_rentals.each do |rental|
result += "\t#{rental.movie.title}\t#{rental.charge}\n"
end
result += "Amount owed is #{total_charge}\n"
result += "You earned #{total_frequent_renter_points} frequent renter points"
end
def html_statement
result = "<h1>Rentals for <em>#{name}</em></h1><p>\n"
_rentals.each do |rental|
result += "#{rental.movie.title}: #{rental.charge}<br>\n"
end
result += "<p>You owe <em>#{total_charge}</em></p>\n"
result += "On this rental you earned <em>#{total_frequent_renter_points}</em> frequent renter points<p>"
end
end
class StatementThe next step is to alter Customer to use our new Statement class.
end
module TextStatement
end
module HtmlStatement
end
class CustomerNext, Martin begins to move the differing behavior to separate methods.
def statement
Statement.new.extend(TextStatement).value(self)
end
def html_statement
Statement.new.extend(HtmlStatement).value(self)
end
end
module TextStatement
def value(customer)
result = "Rental Record for #{customer.name}\n"
customer.rentals.each do |rental|
result += "\t#{rental.movie.title}\t#{rental.charge}\n"
end
result += "Amount owed is #{customer.total_charge}\n"
result += "You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end
module HtmlStatment
def value(customer)
result = "<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
customer.rentals.each do |rental|
result += "#{rental.movie.title}: #{rental.charge}<br>\n"
end
result += "<p>You owe <em>#{customer.total_charge}</em></p>\n"
result += "On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
module TextStatementThe final (hopefully obvious) step is to pull up the value method.
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end
def header_string(customer)
"Rental Record for #{customer.name}\n"
end
def each_rental_string(rental)
"\t#{rental.movie.title}\t#{rental.charge}\n"
end
def footer_string(customer)
"Amount owed is #{customer.total_charge}\n" +
"You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end
module HtmlStatement
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end
def header_string(customer)
"<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
end
def each_rental_string(rental)
"#{rental.movie.title}: #{rental.charge}<br>\n"
end
def footer_string(customer)
"<p>You owe <em>#{customer.total_charge}</em></p>\n" +
"On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
class StatementAt this point, forming a template method by using extend should be clear. But why use extend instead of inheritance? The answer is you would use extend if the modules you were creating could be used to extend various classes.
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end
end
module TextStatement
def header_string(customer)
"Rental Record for #{customer.name}\n"
end
def each_rental_string(rental)
"\t#{rental.movie.title}\t#{rental.charge}\n"
end
def footer_string(customer)
"Amount owed is #{customer.total_charge}\n" +
"You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end
module HtmlStatement
def header_string(customer)
"<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
end
def each_rental_string(rental)
"#{rental.movie.title}: #{rental.charge}<br>\n"
end
def footer_string(customer)
"<p>You owe <em>#{customer.total_charge}</em></p>\n" +
"On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
For example, let's imagine that the next requirement of our application is to display the above information for only the previous month. The current statement class gives a list of each rental associated with a customer for all months. To satisfy our new requirement we could create a MonthlyStatement class similar to the code below.
MonthlyStatementThe advantage to the module approach and mixins is now clear: if we had chosen inheritance we would not need to create a TextMonthlyStatement class and a HtmlMonthlyStatement class. However, because we chose to use modules instead of inheritance, we can simply mixin their behavior and achieve reuse without additional classes.
def value(customer)
result = header_string(customer)
rentals = customer.rentals.collect { |rental| rental.date > DateTime.now - 30 }
rentals.each do |rental|
result += each_rental_string(rental)
end
end
end
class Customer
def statement
Statement.new.extend(TextStatement).value(self)
end
def html_statement
Statement.new.extend(HtmlStatement).value(self)
end
def monthly_statement
MonthlyStatement.new.extend(TextStatement).value(self)
end
def monthly_html_statement
MonthlyStatement.new.extend(HtmlStatement).value(self)
end
end
Monday, September 18, 2006
A Ruby DSL for generating SQL
On my past 2 projects I've needed the ability to create ad-hoc SQL statements. These statements, following creation, are executed by using ActiveRecord::Base.connection.execute. On the first project we largely used strings to represent our required SQL. However, on our second project we decided to create a DSL that allowed us to stay in our comfortable Ruby world. That DSL is a bit more heavy-weight; however, I took the experience I gained from that project and put together a light-weight version that I've released on RubyForge.org.
The idea of the DSL was to keep as similar to SQL as possible. Below are examples of both the actual SQL and Ruby version that allowed us to generate the SQL.
If you are lucky you may never have any need for such a library; however, if you use find_by_sql on ActiveRecord::Base or select_values, select_value, or select_one on ActiveRecord::Base.connection you may want to give the DSL a look.
To install SQL DSL you can:
For more information check out the SQL DSL documentation on RubyForge.org
The idea of the DSL was to keep as similar to SQL as possible. Below are examples of both the actual SQL and Ruby version that allowed us to generate the SQL.
Select column1 from table1The DSL does not contain any field validation or verify that the columns exist in the specified tables or any other magic. Currently, it's sole purpose is to allow you to easily write SQL with Ruby code.
where column2 = 12
and column 3 = 13
Select[:column1].from[:table1].where do
equal :column2, 12
equal :column3, 13
end
insert into table1 (column1, column2, column3) values (10, 'book', 'start')
Insert.into[:table1][:column1, :column2, :column3].values(10, 'book', 'start')
update table1 set column1 = 12, column2 = 'book'
where column1 = 10
Update[:table1].set[:column1=>12, :column2=>'book'].where do
equal :column1, 10
end
delete from table1 where column1 = 12
Delete.from[:table1].where do
equal :column1 = 12
end
If you are lucky you may never have any need for such a library; however, if you use find_by_sql on ActiveRecord::Base or select_values, select_value, or select_one on ActiveRecord::Base.connection you may want to give the DSL a look.
To install SQL DSL you can:
gem install sqldslOnce installed all you need to do is
require 'sqldsl' and all should be well.For more information check out the SQL DSL documentation on RubyForge.org
Thursday, September 14, 2006
Ruby Stub Variations: Struct
Ruby Stub Variations: Introduction
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
In my last entry I described how TestStub provided a concise syntax for defining stubs on the fly. However, I always consider it a win when I can remove code from the codebase without removing functionality.
Ruby provides a Struct class that allows you to define classes on the fly. From the Ruby documentation:
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
In my last entry I described how TestStub provided a concise syntax for defining stubs on the fly. However, I always consider it a win when I can remove code from the codebase without removing functionality.
Ruby provides a Struct class that allows you to define classes on the fly. From the Ruby documentation:
A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.Struct also provides a one line solution to the example test.
def test_values_are_appened_to_insert_statementThe syntax of Struct doesn't seem as natural since the proliferation of using hashes as parameters, but Struct does provide the flexability of creating a new class and initializing at a later time. Struct works well and does not suffer from any of the limitations of the other examples.
statement = Insert.into[:table_name].values do
Struct.new(:to_sql).new('select column1, column2 from table2')
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Wednesday, September 13, 2006
Ruby Stub Variations: TestStub
Ruby Stub Variations: Introduction
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
As I mentioned in my last entry, OpenStruct provides the desired simplicity when creating a stub. However, OpenStruct's inability to stub previously defined methods made it painful to work with when stubbing ActiveRecord::Base subclass instances. To resolve this issue my team borrowed some of the code from OpenStruct and wrote their own TestStub class. I previously wrote about this decision so I wont go too deep into detail; however, the general idea is that defining methods, instead of depending on a hash, resolved this issue. The implementation we ended up using was a bit simpler than the previous example though.
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
As I mentioned in my last entry, OpenStruct provides the desired simplicity when creating a stub. However, OpenStruct's inability to stub previously defined methods made it painful to work with when stubbing ActiveRecord::Base subclass instances. To resolve this issue my team borrowed some of the code from OpenStruct and wrote their own TestStub class. I previously wrote about this decision so I wont go too deep into detail; however, the general idea is that defining methods, instead of depending on a hash, resolved this issue. The implementation we ended up using was a bit simpler than the previous example though.
class TestStubTestStub provided us with the same ease of use that OpenStruct provided, thus the solution to example test is basically the same.
def initialize(*should_respond_to)
@table = {}
should_respond_to.each do |item|
create_readers(item) and next if item.kind_of? Hash
create_writer(item) and next if item.kind_of? Symbol
end
end
def create_readers(item)
item.each_pair do |key, val|
self.class.send(:define_method, key.to_sym) { val }
end
end
def create_writer(item)
self.class.send(:define_method, :"#{item}=") { }
end
end
def test_values_are_appened_to_insert_statementTestStub never gave us any trouble; however, it was one more piece of code (and tests) to maintain.
statement = Insert.into[:table_name].values do
TestStub.new(:to_sql=>'select column1, column2 from table2')
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Tuesday, September 12, 2006
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: Introduction
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
Shortly after I begin to program full time using Ruby I was exposed to OpenStruct. I was quite pleased with the simplicty OpenStruct offered. OpenStruct allows you to create objects with their attributes initialized. For example:
Another issue with OpenStruct is that it does not respond as expected if you specify a value for an already defined method. My team noticed this behavior while using an OpenStruct instance in place of a ActiveRecord::Base subclass instance. The test required the OpenStruct instance to respond to
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
Shortly after I begin to program full time using Ruby I was exposed to OpenStruct. I was quite pleased with the simplicty OpenStruct offered. OpenStruct allows you to create objects with their attributes initialized. For example:
require 'ostruct'OpenStruct provided value by allowing me to easily create stubs in one line of code. The code below represents a more robust version of the example test. OpenStruct helps reduce the fragility of the test by removing the dependency on the Select class.
record = OpenStruct.new(:name=>'jay')
puts record.name # -> jay
def test_values_are_appened_to_insert_statementDespite the value of OpenStruct, it also has some limitations. The first issue we encountered was that it did not respond as expected when the OpenStruct instance was frozen.
statement = Insert.into[:table_name].values do
OpenStruct.new(:to_sql=>'select column1, column2 from table2')
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Another issue with OpenStruct is that it does not respond as expected if you specify a value for an already defined method. My team noticed this behavior while using an OpenStruct instance in place of a ActiveRecord::Base subclass instance. The test required the OpenStruct instance to respond to
id; however, the number that was returned did not match the value passed in the constructor. The following failing test should demonstrate the described issue.require 'test/unit'This issue stems from the current implementation of OpenStruct. OpenStruct stores it's attribute values in a Hash. When you attempt to access an attribute the call is actually delegated to method_missing. OpenStruct's implementation of method_missing returns the value from the Hash if it finds a matching key, otherwise nil. Unfortunately, method_missing will never be called if a method, such as id, is previously defined.
require 'ostruct'
class OpenStructTest < Test::Unit::TestCase
def test_id
assert_equal 2, OpenStruct.new(:id=>2).id
end
end
Monday, September 11, 2006
Ruby Stub Variations
The majority of my Unit Tests focus on testing individual classes one method or behavior at a time. To facilitate this type of testing the class under test often collaborates with stub classes. Ruby offers several choices for stubbing.
To demonstrate usage for the various types of stubs I'll use a test from our test suite and show the differing implementations. The example comes from our tests that ensure our SQL DSL behaves as expected. This test verifies that
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
To demonstrate usage for the various types of stubs I'll use a test from our test suite and show the differing implementations. The example comes from our tests that ensure our SQL DSL behaves as expected. This test verifies that
to_sql is called on the object that is in the block being passed to the values method and the return value of to_sql is appended to the sql being generated by the Insert instance.def test_values_are_appened_to_insert_statementThe above code uses both the Insert and Select classes within the test. Using both classes does produce a passing test. However, a more robust implementation would allow the behavior of Select to be changed without breaking any of the tests within Insert. The next several entries will focus on the various types of stubs I've used in the past to solve this issue.
statement = Insert.into[:table_name].values do
Select[:column1, :column2].from[:table2]
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba
Friday, September 08, 2006
Ruby instance_exec aka instance_eval with parameters
Updated: Changed the instance_exec implementation to a better version, also written by Mauricio. See comments for more info.
Recently we were extracting some common behavoir to a class method. The behavior of the methods being defined was similar; however, it did differ slightly so we needed the ability to pass a block to the method. Unfortunately, we needed the block to take a parameter and also execute in the scope of the instance.
For example, the
In Ruby 1.9 instance_exec should solve this problem; however, for the time being you can find an implementation for 1.8.4 that was written by Mauricio Fernandez.
Recently we were extracting some common behavoir to a class method. The behavior of the methods being defined was similar; however, it did differ slightly so we needed the ability to pass a block to the method. Unfortunately, we needed the block to take a parameter and also execute in the scope of the instance.
For example, the
bubble method from my previous example is used to define methods dynamically. We also needed the bubble method to add a string to an array.class << ObjectThe above implementation will work for this code:
def bubble(*args, &block)
args.each do |method_name|
define_method(method_name) do
instance_eval(&block) if block_given?
self
end
end
end
end
class FooHowever, if you could pass a parameter to the block the code could become:
bubble :return_self do
some_array << 'return_self'
end
bubble :return_self2 do
some_array << 'return_self2'
end
end
class FooUnfortunately, instance_eval does not currently allow you to pass parameters.
bubble :return_self do |method_name|
some_array << method_name.to_s
end
end
In Ruby 1.9 instance_exec should solve this problem; however, for the time being you can find an implementation for 1.8.4 that was written by Mauricio Fernandez.
class ObjectUsing instance_exec allows us to use this implementation for bubble:
module InstanceExecHelper; end
include InstanceExecHelper
def instance_exec(*args, &block)
begin
old_critical, Thread.critical = Thread.critical, true
n = 0
n += 1 while respond_to?(mname="__instance_exec#{n}")
InstanceExecHelper.module_eval{ define_method(mname, &block) }
ensure
Thread.critical = old_critical
end
begin
ret = send(mname, *args)
ensure
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
end
ret
end
end
class << ObjectThis allows us to dry up the Foo code to be:
def bubble(*args, &block)
args.each do |method_name|
define_method(method_name) do
instance_exec(method_name, &block) if block_given?
self
end
end
end
end
class FooFor more info on instance_exec in Ruby 1.9 check out Mauricio's write-up.
bubble :return_value1, :return_value2 do |method_name|
some_array << method_name
end
end
Ruby Asserting Equality with True
Bill Caputo wrote a blog entry several months ago stating that he preferred tests that assert equality over tests that simply assert truth. If I remember correctly the main point was that an error message such as
I agree with Bill and think it's a great guideline to follow when writing tests. Unfortunately, there are also times when I need to assert truth. These tests usually appear when I need to test a method that should return true or false. In these situations I've found it valuable to use
The largest reason for this choice is because Ruby treats everything that is not nil or false as true. Therefore, if you are testing the
1 expected but was 2 is much more descriptive than false is not true.I agree with Bill and think it's a great guideline to follow when writing tests. Unfortunately, there are also times when I need to assert truth. These tests usually appear when I need to test a method that should return true or false. In these situations I've found it valuable to use
assert_equal instead of assert when programming in Ruby.The largest reason for this choice is because Ruby treats everything that is not nil or false as true. Therefore, if you are testing the
coded? method and you have an implementation error such as:def coded?Your test will still pass if the test is coded as:
state = :coded
end
def test_coded?However, this test will fail:
assert obj.coded?
end
def test_coded?Clearly, you should also have a test that verifies that
assert_equal true, obj.coded?
end
coded? is false; thus, better coverage mitigates this risk. However, I still prefer the assert_equal test implementation because I feel it makes my test suite more robust.
Wednesday, September 06, 2006
Alternative Story Card Format
The common story card format is
Ownership can be very important when stakeholders need to collaborate on determining scope. Therefore, I prefer explicitly naming the owner of the card.
For more information on Story Cards check out the c2 wiki.
As a [ person ]Unfortunately, I don't believe that it creates the accountability that it attempts to show. For example, a story card could be:
I would like to [ action ]
so that [ reason for action ]
As a script authorThe above story card would be a valid story card; however, it doesn't tell me who introduced this story card. What if the card was introduced by a stakeholder who will actually never play the role of script author. Perhaps it was created in anticipation of an auditing requirement that has yet to be defined. In the end, the functionality may end up YAGNI.
I'd like to see a diff of current scripts against previous scripts
so that I can verify alterations
Ownership can be very important when stakeholders need to collaborate on determining scope. Therefore, I prefer explicitly naming the owner of the card.
Jay would like to see a diff of current scripts against previous scripts so that he can verify alterations.Using this format also ensures that only customers are creating requirements.
For more information on Story Cards check out the c2 wiki.
Tuesday, September 05, 2006
Ruby/Rails Unit Testing in less than 1 second
I previously wrote about removing the database dependency from Ruby on Rails Unit Tests. I'm pleased to say that several months later my team continues to write unit tests that do not require database access. As a result, our unit tests run quite quickly:
Mocha is my new favorite mocking framework. Mocha's syntax is intuative and the mocks are auto-verified.
For more information on removing the database dependency check out this entry and for more info on Stubba and Mocha check out the RubyForge page.
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loaderHowever, there is another factor that contributes to our test time: Stubba and Mocha. Stubba and Mocha have become tools that I would not want to live without.
Started
....................................................................................................................................
Finished in 0.555897 seconds.
132 tests, 219 assertions, 0 failures, 0 errors
Mocha is my new favorite mocking framework. Mocha's syntax is intuative and the mocks are auto-verified.
def test_execute(command='sql string', connection=mock)Stubba is similar to Mocha except it adds mock and stub capabilities to concrete classes.
connection.expects(:execute).with(command)
SqlExecutor.execute(command, connection)
end
def test_execute(command='sql string')Stubba can also be used for easy white box unit testing of specific methods. Stubba allows you to mock some methods of a concrete class while testing the actual implementations of the other methods.
DatabaseConnection.expects(:execute).with(command)
SqlExecutor.execute(command)
end
def test_parse(text='any text')Both Stubba and Mocha allow our tests to be concise and descriptive while increasing test performance.
Parser.expects(:preprocess).returns('condition.add')
Builder.expects(:build)
Parser.parse(text)
end
For more information on removing the database dependency check out this entry and for more info on Stubba and Mocha check out the RubyForge page.

