Port of schuchert.wikispaces.com


FirstPass

FirstPass

So I want to learn Ruby using a TDD approach. So I started by installing The Ruby Development Tools Eclipse plugin.

Well it turns out to run Ruby you still need to install a Ruby Interpreter, which I did.

Here are some very early examples trying to use TDD:

DieTest

require 'test/unit'
require 'die'

class DieTest < Test::Unit::TestCase
  
  def test_roll
    rolledValues = Array.new
    for num in (0..6)
      rolledValues[num] = 0
    end
    
    10000.times do
      v = Die.new.roll
      rolledValues[v] = rolledValues[v] + 1
    end
    
    assert_equal(0, rolledValues[0])
    for i in (1..6)
      assert(rolledValues[i] > 1000, 'missing number: ' + i.to_s)
    end
  end
  
end

Die

class Die
  def initialize()
    roll
  end
  
  def roll
    @faceValue = rand(6) + 1
  end 
  
  def faceValue
    @faceValue
  end
end

PairOfDiceTest

require 'test/unit/testcase'
require 'test/unit/autorunner'
require 'pair_of_dice'

class PairOfDiceTest < Test::Unit::TestCase
 
  def test_roll_returns_valid
    p = PairOfDice.new
    v = p.roll
    assert(v >=2 && v <= 12)
  end 
  
end

PairOfDice

require 'die'

class PairOfDice
  def initialize()
    @d1 = Die.new
    @d2 = Die.new
  end  
  
  def roll
    @d1.roll + @d2.roll
  end
  
  def faceValue
    @d1.faceValue + @d2.faceValue
  end
end

This works, however I want to be able to run all of my tests in one fell swoop. In Eclipse using Java, I simply right-click on a project and select Run->Junit Tests and it’s all good. This feature doesn’t seem to be available in Test::Unit (the Ruby equivalent) so after several attempts, I think I’ve got what I’m looking for:

Suite

require 'test/unit'
require 'find'

def allFiles
  files = Array.new
  Find.find('./') { |f| 
    if(f =~ /_test/)
      f = f.sub(/\.\//, "").sub(/\.rb$/,"")
      files.push(f) 
    end
  }
  files
end

allFiles().each {|f| require f}

This was adequate until I checked my code into subversion. When I did that, I had the original versions of the files in the .svn directory. I then updated this to prune the .svn directory:

require 'test/unit'
require 'find'

def allFiles
  files = Array.new
  Find.find('./') { |f| 
    if(f =~ /\.svn/)
      Find.prune if f =~ /\.svn/
    end
    if(f =~ /_test/)
      f = f.sub(/\.\//, "").sub(/\.rb$/,"")
      files.push(f) 
    end
  }
  files
end

allFiles().each {|f| require f}

Of course, on the Ruby Forum, Ryan Davis gave me a MUCH more concise (and frankly I think MUCH better) version of this:

(%w(test/unit) + Dir['**/*_test.rb']).each { |f| require f }

All “require”d files are read in using a single array. To create the array we first create an array using words (in this case it saves nothing to use %w(test/unit) versus [‘test/unit’]. The + operation on an array adds the contents of one array to another and the Dir class’s [] method recursively finds files using a syntax I’m familiar with from ant.

This generates an array that looks like the following:

   ['test/unit', 'die_test', 'pair_of_dice_test']

Then we require each of theses. By requiring test/unit, all other files read in using require that inherit from Test::Unit::TestCase are automatically added to a suite.

Having managed the first version, I continued with the first release of Monopoly.


Comments

" Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.