Tuesday, August 29, 2006

Ruby Unit Test Parameters

My project team recently started following a new convention of adding parameters to the test methods in our code base. However, the parameters are not arbitrary nor do they represent each variable used in the test. Instead they represent the arguments that are passed to the method under test.

We found this pattern by noticing that our tests generally focused on testing one method at a time. In the test methods we decided to clone the parameters that the method under test required.

For example, the method and test for addition could be:
class MathTest < Test::Unit::TestCase
def test_add(x=1, y=2)
assert_equal 3, Math.add(x,y)
end
end

class Math
def add(x, y)
x + y
end
end
A benefit to this style of test development is the ability to easily see which method is under test and what the values are of the arguments passed to the method under test. However, this does introduce a maintainability issue. Clearly, changing the parameters to the method under test will not automatically change the parameters to the test method. Additionally, when methods have multiple execution paths, thus requiring multiple test methods, the naming convention begins to break down.

When the effort is made to keep the definitions between the test and method under test synchronized this test definition convention has been shown to increase maintainability.

Friday, August 25, 2006

Use Ruby Class Methods to Remove Duplication

One of my favorite features of Ruby is the ability to use class methods to remove duplication. When I'm developing if I find methods that are similar (or identical) I like to extract these methods and define them dynamically using class methods. I've previously written about Attribute Initializer, which was one of the first methods that I abstracted after noticing the duplication in the code base.

Another example pulled from an actual code base is the bubble method:
def bubble(*args)
args.each do |method_name|
define_method(method_name) do
self
end
end
end
The bubble method is used in our code base to facilitate a Domain Specific Language that reads like natural language. The bubble method was extracted from duplicate methods in the code base such as:
def flag
self
end

def as
self
end
However, the above defined bubble method allows the flag and as methods to be defined simply by using:
bubble :flag, :as
The current code base I'm working in has several of these class methods that do everything from simply returning self to creating entire object graphs.

The reduced code duplication is an obvious benefit to this style of programming. However, some developers dislike this style of programming because they feel that the class methods obscure intent and decrease readability. There is clearly a trade-off and in the end it may simply be a coding style choice.

Sunday, August 20, 2006

Sync your Samsung phone with your Mac Address Book using Bluetooth

I bought a new Samsung phone this weekend. Overall I am quite happy with the phone; however, it is missing one key feature: it does not work with iSync. Some quick research revealed that Samsung failed to implement SyncML; therefore, sync'ing with my Mac wasn't going to happen.

Despite the fact that using iSync isn't an option, I did find some information on how I could transfer my numbers from Address Book to my new phone. The steps I took varied slightly, thus the reason for this blog entry.
  1. Open Address Book
  2. Address Book -> Preferences -> vCard: Set vCard Format to 2.1.
  3. File -> Export Group vCard: Save Group vCard to a new folder anywhere.
  4. Download vCard Splitter and install.
  5. Open your saved Group vCard using vCard Splitter.
  6. System Preferences -> Bluetooth -> Devices -> Set Up New Device: Pair your phone with your Mac.
  7. System Preferences -> Bluetooth -> Settings: Show Bluetooth status in the menu bar.
  8. Menu Bar -> Bluetooth Status -> Turn Bluetooth On
  9. Menu Bar -> Bluetooth Status -> Send File -> Select all the vCards generated by vCard Splitter -> Select your paired phone.
At this point your phone should receive each vCard one at a time and add them to your phone's contact list. It's not the best long term solution; however, it will get you started and is much better than having to enter people one at a time.

Tuesday, August 15, 2006

Removing kind_of? and is_a? from your code

The Object class of Ruby contains the identical methods is_a? and kind_of?. They take a single argument, a class, and returns true if class is the class of the object, or if class is one of the superclasses of the object or modules included in object. The kind_of? (or is_a?) method is generally used for determining behavior based on the type of class of a parameter.

Most often I've seen kind_of? appearing in methods that need different behavior depending on the class type of an argument. For example, in a SQL DSL I was recently working on we had a method that would surround string objects with quotes, but would simply call to_s on other objects such as instances of Symbol or Fixnum.
def columns(*args)
args.each |element|
if element.kind_of? String
@column_array << "'#{element}'"
else
@column_array << element.to_s
end
end
This code does solve the problem; however, I believe that the code is structured in response to the languages inability to overload methods and behave differently based on type.

An alternative solution is to take advantage of duck typing. If the method were rewritten to execute a method that any class could respond to, the if..else statement becomes unnecessary.
def columns(*args)
args.each |element|
@column_array << element.to_sql
end
end
Clearly, for this example to work each argument must respond to the to_sql method. Because Ruby's classes can be re-opened this change is trivial.
class String
def to_sql
"'#{self}'"
end
end

class Fixnum
def to_sql
self
end
end

class Symbol
def to_sql
self.to_s
end
end
An added benefit to duck typing is that you can pass any object that responds to to_sql. For example, if you wanted a class that would represent null in the database you could define a class that only responds to the to_sql method.
class DBNull
def to_sql
'null'
end
end
For more information on Duck Typing see the chapter in Programming Ruby.

Friday, August 11, 2006

Alternative to Dependency Injection

Generally, when a class has a dependency it is preferred to use Inversion of Control. The popular methods for specifying the dependency are setter and constructor injection. Dependency Injection is one of my favorite patterns because it facilitates loosely coupled code that is easily testable. However, recently I found an alternative solution that can be used when DI is used solely for testing.

Let's start with a class** (CellPhone) containing a dependency (SimCard):
class CellPhone
def initialize
@sim_card = SimCard.new
end

def save_number(number)
@sim_card.save_number(number)
end

def include_number?(number)
@sim_card.include_number?(number)
end
end
In this example it is not clear how you could test the CellPhone class without depending on the SimCard class. This can create problems such as the SimCard class raising errors like SimCardFullError when you are actually only trying to test the CellPhone class. A simple solution is to introduce Constructor Injection to decouple the SimCard class.
class CellPhone
def initialize(sim_card)
@sim_card = sim_card
end

def save_number(number)
@sim_card.save_number(number)
end

def include_number?(number)
@sim_card.include_number?(number)
end
end
This solution does work; however, you now need to create an instance of the SimCard class before you can create an instance of the CellPhone class. In the case of this example additional work has been created because the CellPhone never needs to use different types of SimCards except when testing.

There is an alternative solution that allows you to stub the behavior of a class without stubbing the entire class. This alternative solution is available because Ruby allows you to re-open classes. To see how this works we will need a test.
class CellPhoneTest < Test::Unit::TestCase
def test_save_number
phone = CellPhone.new.save_number('555-1212')
assert phone.include_number?('555-1212')
end
end
This test will pass with the first implementation assuming the SimCard class does not cause a problem. The change to test using the second implementation is straightforward enough that I don't feel it's necessary to demonstrate. However, what I do find interesting is how I can test CellPhone in isolation without changing the first implementation. The way to achieve this is to re-open the class within the test and alter the behavior of the class.
class CellPhoneTest < Test::Unit::TestCase
def setup
class << SimCard
alias :save_old :save_number
alias :include_old :include_number?
def save_number(number)
end

def include_number?(number)
true
end
end
end

def teardown
class << SimCard
alias :save_number :save_old
alias :include_number? :include_old
end
end

def test_save_number
phone = CellPhone.new.save_number('555-1212')
assert phone.include_number?('555-1212')
end
end
As you can see in the example the CellPhone class tests are no longer brittle despite the dependency on SimCard.

It's important to note that for our example it is assumed that CellPhone will always depend on the SimCard class. If it needed to depend on different types of SimCards then Constructor Injection would be necessary anyway.

While our solution does work it's not entirely elegant. Luckily, James Mead pointed me at Mocha, a library that facilitates this type of behavior switching. Using Stubba the test becomes much cleaner.
require 'stubba'

class CellPhoneTest < Test::Unit::TestCase
def test_save_number
SimCard.stubs(:new).returns(stub_everything(:include_number? => true))
phone = CellPhone.new.save_number('555-1212')
assert phone.include_number?('555-1212')
end
end
For more information check out the documentation for Mocha.



** Of course, the real class def would be
class CellPhone
extend Forwardable

def_delegators :@sim_card, :save_number, :include_number?

def initialize
@sim_card = SimCard.new
end
end