Wednesday, April 15, 2009

TDD : Test Driven Development

Introduction : Mastermind


Créer un Mastermind en ruby : Tests et code source d'Emmanuel Gaillot. Voir l'installation de l'environnement a la fin de l'article.



Discussion


Reactions :


  • TDD fonctionne bien pour un mastermind, mais qu'en est-il avec du "vrai code" ?

  • TDD itère par petites étapes: est-ce trop lent pour etre productif ? <-> Augmenter la confiance dans son code, moins de bugs, qualité du code, refactoring plsu facile

  • TDD coute cher des le début, comment convaincre mon manager ?

  • A quel moment est-on sur que les tests sont suffisants pour une fonctionnalité?

  • Si on cherche absolument a faire passer les tests il suffit de coder des fakes et passer a autre chose. Non: le fake ne sert qu'a avancer dans le code, il faut ensuite passer par une phase de refactoring.



Liens web présentés pendant la discussion :



MasterMind Source code


Tests :


require "test/unit"
require "lib/Arbitre"

class ArbitreTest < Test::Unit::TestCase

def assert_evalue resultatAttendu, secret, proposition
assert_equal resultatAttendu, Arbitre.new.evalue(secret, proposition)
end

def testToutFauxPourCombinaisonUnSeulElement
assert_evalue [bienPlaces = 0, malPlaces = 0],
secret = [:bleu], proposition = [:rouge]
end

def testToutJustePourCombinaisonUnSeulElement
assert_evalue [1, 0], [:bleu], [:bleu]
assert_evalue [1,0], [:rouge], [:rouge]
end

def testPlusieursElementsJustesSurCombinaisonPlusieursElements
assert_evalue [1, 0], [:bleu, :rouge], [:bleu, :vert]
assert_evalue [1,0], [:bleu, :vert], [:rouge, :vert]
assert_evalue [2, 0], [:bleu, :vert, :jaune], [:bleu, :vert, :rouge]
end

def testQuelquesElementsMalPlacesParmiPlusieurs
assert_evalue [0, 1], [:bleu, :mauve], [:mauve, :rouge]
assert_evalue [0, 2], [:bleu, :bleu, :mauve, :mauve], [:mauve, :mauve, :vert, :vert]
end

def testNeCompterLesMauvesQueSiIlYEnADansLeSecret
assert_evalue [0,0] , [:bleu, :vert], [:rouge,:mauve]
end

def testUnMalPlaceNeDoitEtreCompteQuUneFois
assert_evalue [0, 1], [:bleu, :bleu, :mauve], [:mauve, :mauve, :rouge]
end

def testJauneAussiPeutEtreMalPlace
assert_evalue [0,1], [:bleu,:bleu,:jaune], [:jaune,:jaune,:rouge]
end

def testToutesLesCouleursPeuventEtreMalPlacees
assert_evalue [0,6],
[:bleu,:rouge,:jaune,:vert,:mauve,:noir],
[:rouge,:jaune,:vert,:mauve,:noir,:bleu]
end

end


Code Arbitre.rb :


class Arbitre

def initialize
@bienPlaces = 0

@couleursDansSecret = nouveauCompteurCouleurs
@couleursDansProposition = nouveauCompteurCouleurs
end

def nouveauCompteurCouleurs
resultat = Hash.new
resultat.default = 0
resultat
end

def comptePions couleurSecret, couleurProposition

if (couleurSecret == couleurProposition)
@bienPlaces += 1
else

@couleursDansSecret[couleurSecret] += 1
@couleursDansProposition[couleurProposition] += 1
end
end

def nbMalPlacesPourCouleur c
[@couleursDansSecret[c], @couleursDansProposition[c]].min
end

def somme liste
liste.inject(0) {|x, y| x + y}
end

def malPlaces
somme (@couleursDansSecret.keys.map {|c| nbMalPlacesPourCouleur c})
end

def evalue secret, proposition
secret.each_index do |i|
comptePions secret[i], proposition[i]
end
[@bienPlaces,malPlaces]
end
end



Installation de l'environnement


Setup for windows :


  • One-click install ruby (with gem option)

  • Install autotest with this command : gem install zentest

  • Install colors for the autotest results : gem install win32console

  • Add to the beginning of the file C:\Ruby\lib\ruby\gems\1.8\gems\ZenTest-4.0.0\lib\autotest.rb the line : require 'Win32/Console/ANSI'

  • Create C:\Mastermind\.autotest and add this line to the file : require 'autotest/redgreen'

  • Create an empty file C:\Mastermind\spec\spec.opts

  • Create the source code file in Mastermind\lib\Arbitre.rb

  • Create your test file (the filename must start with "test_") : C:\Mastermind\test\test_Arbitre.rb

  • You can start autotest with the command C:\Mastermind\autotest -v