TDD/BDD in Ruby - Chapter 6

To-Do List

$5 + 10 CHF = $10 if rate is 2:1
$5 * 2 - $10
Make "amount" private
Dollar side effects?
Money rounding?
equals()
hashCode()
Equal null
Equal object
5 CHF * 2 - 10 CHF
Dollar/Franc duplication
Common equals
Common times
Compare Francs with Dollars

Test::Unit Code


require 'test/unit'
require 'dollar.rb'
require 'franc.rb'

class TestDollar < Test::Unit::TestCase
  def test_multiplication
    five = Dollar.new(5)
    assert_equal(five.times(2), Dollar.new(10))
    assert_equal(five.times(3), Dollar.new(15))
  end

  def test_franc_multiplication
    five = Franc.new(5)
    assert_equal(five.times(2), Franc.new(10))
    assert_equal(five.times(3), Franc.new(15))
  end

  def test_equality
    assert_equal(Dollar.new(5), Dollar.new(5))
    assert_not_equal(Dollar.new(5), Dollar.new(6))
    assert_equal(Franc.new(5), Franc.new(5))
    assert_not_equal(Franc.new(5), Franc.new(6))
  end
end

RSpec Code


require 'spec'
require 'dollar.rb'
require 'franc.rb'

class DollarSpecification < Spec::Context
  def dollar_multiplication
    five = Dollar.new(5)
    five.times(2).should.equal Dollar.new(10)
    five.times(3).should.equal Dollar.new(15)
  end

  def franc_multiplication
    five = Franc.new(5)
    five.times(2).should.equal Franc.new(10)
    five.times(3).should.equal Franc.new(15)
  end

  def equality
    Dollar.new(5).should.equal Dollar.new(5)
    Dollar.new(5).should.not.equal Dollar.new(6)
    Franc.new(5).should.equal Franc.new(5)
    Franc.new(5).should.not.equal Franc.new(6)
  end
end

Money Class Code


class Money
  attr_reader :amount

  def eql?(object)
    self == (object)
  end

  def ==(object)
    object.equal?(self) ||
      (object.instance_of?(self.class) && object.amount == @amount)
  end
end

Dollar Class Code


require 'money.rb'

class Dollar < Money
  def initialize(amount)
    @amount = amount
  end

  def times(multiplier)
    Dollar.new(@amount * multiplier)
  end
end

Franc Class Code


require 'money.rb'

class Franc < Money
  def initialize(amount)
    @amount = amount
  end

  def times(multiplier)
    Franc.new(@amount * multiplier)
  end
end

Notes & Quotes

  • Make sure to reconcile multiple implementations - ==() in this case - before eliminating the redundant code