Wednesday, May 31, 2006

Use class methods for stubs

Since I believe in unit testing one concrete class at a time I frequently use stubs in my tests. These stubs always return the same value and are unimportant to the current test.

For example, assume you have an Employee class that contains check_email behavior.
class Employee
def initialize(cell_phone, laptop)
@cell_phone = cell_phone
@laptop = laptop
end

def check_email(user, password)
if @laptop.working?
@laptop.check_email(user, password)
else
@cell_phone.check_email(user, password)
end
end
end
In the above example Employee depends on cell_phone and laptop. When testing check_email you should have (at least) two tests, one for the case where @laptop.working? is true and one where it returns false. The second scenario (where @laptop.working? is false) is perfect for stub usage.
class EmployeeTest < Test::Unit::TestCase
class StubLaptop
def working?
false
end
end

...
def test_when_laptop_is_not_working_cell_phone_is_used
# code for setting up a mock for cell_phone
employee = Employee.new(mock_cell_phone, StubLaptop.new)
employee.check_email('jay', 'password')
# code to verify mock
end
end
The above test is correct; however, it can be slightly changed. Because of duck typing and the fact that stubs should always return a constant value it is possible to use class methods instead of instance methods. This relieves you from needing a new instance for each stub.
class EmployeeTest < Test::Unit::TestCase
class StubLaptop
def self.working?
false
end
end

...
def test_when_laptop_is_not_working_cell_phone_is_used
# code for setting up a mock for cell_phone
employee = Employee.new(mock_cell_phone, StubLaptop)
employee.check_email('jay', 'password')
# code to verify mock
end
end
Post a Comment