JeuWeb - Crée ton jeu par navigateur
Pratiquez-vous TDD sur des projets personnels ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Pratiquez-vous TDD sur des projets personnels ? (/showthread.php?tid=5985)



Pratiquez-vous TDD sur des projets personnels ? - Sephi-Chan - 18-02-2012

Hello,

En ce moment, je fais un peu de refactoring sur Conquest on Rails en pratiquant le développement piloté par les tests (Test Driven Development) et je me posais la question : est-ce que certains d'entre-vous le pratiquent sur leurs projets de jeux ?

Et à défaut de TDD, est-ce que vous écrivez des tests automatisés pour vos différentes systèmes ?

Si oui, ça pourrait être intéressant d'en discuter plus souvent sur le forum : c'est parfois difficile de déterminer quoi tester, et également difficile d'écrire un code robuste (couplage, responsabilité, etc.).



RE: Pratiquez-vous TDD sur des projets personnels ? - niahoo - 18-02-2012

Systématiquement.

Je teste uniquement mes API en codant d'abord les tests, dans une approche top down.
Mais quand je trouve des comportements, des façons de faire récurrentes, je crée des mini sous projets pour sortir de mon projet les briques de bases qui ne lui sont pas spécifiques


RE: Pratiquez-vous TDD sur des projets personnels ? - Sephi-Chan - 18-02-2012

As-tu des paires test/implémentation à présenter (sur un Gist, par exemple) ?
C'est toujours intéressant de voir la manière de spécifier.



RE: Pratiquez-vous TDD sur des projets personnels ? - niahoo - 18-02-2012

faut que je te trouve ça oui, là je pars de chez moi, uppez le topic Smile


RE: Pratiquez-vous TDD sur des projets personnels ? - Ter Rowan - 18-02-2012

je ne fais pas des TDD mais je développe mes tests automatisés après la première version de mon développement :

dès que je crée une méthode d'un objet, je crée autant de cas tests qu'il y a de couples (entrées , sorties) possibles (bon en théorie, dans certains cas c'est pas vraiment possible)

les tests me servent surtout à la non régression

j'en ai pour le moment 820, y a probablement de la redondance et des "trous" fonctionnels mais j'en suis assez content

cas particulier, j'ai des cas tests concernant des méthodes qui utilisent le hasard
de fait j'ai surchargé une fonction de jet de dés :

normal

function Dice($a, $b)
{
return mt_rand ($a, $b);
}

surchargé

function Dice($a, $b)
{
return chance::GetRoll();
}

class chance
{
private static $rolls = array();
private static $cursor = 0;
private static $infinite;

// si infinite = true, alors on boucle sur le tableau des tirages a l infini
public static function SetRolls( $rolls, $infinite = false )
{
if (!is_array($rolls) )
$rolls = array($rolls);
self::$rolls = $rolls;
self::$cursor = 0;
self::$infinite = $infinite;
}

public static function GetRoll()
{
if (self::$cursor >= count(self::$rolls) )
if (self::$infinite)
self::$cursor =0;
else
throw new classError( 1000, array('message' =>'jet de dé non prévu'));

return self::$rolls[self::$cursor ++];
}
}
ainsi lors des tests, je ne laisse pas la place au hasard, je définis avant les appels des méthodes qui utilisent le hasard quel(s) sera(ont) le(s) résultat(s) du dé


RE: Pratiquez-vous TDD sur des projets personnels ? - Sephi-Chan - 18-02-2012

Pour l'aléatoire (et parfois le temps) on utilise des stubs :


Random.stub(:roll).and_return(42) # Pour tout stub.
Random.stub(:roll).with(1, 100).and_return(42) # Pour ne stub qu'avec des arguments précis.



RE: Pratiquez-vous TDD sur des projets personnels ? - niahoo - 27-02-2012

Voilà un extrait d'un test d'une classe simple. C'est pas très propre mais ça fonctionne bien. La classe est triviale aussi
<?php

require_once dirname(__FILE__) . '/../src/behaviours/gen_state.php';

//require_once dirname(__FILE__).'/../behaviours/gen_state.php';


class Test_gen_state extends UnitTestCase {

function __construct() {
parent::__construct();
debug_printer::get_printer()->title(__CLASS__, '-');
}

function test_wrap() {

$this->assertTrue(gen_state::wrap(array()) instanceof gen_state);
$this->assertTrue(count(gen_state::wrap(array())->export()) == 0);
$gs = gen_state::wrap(array('a' => 'b'));
$this->assertTrue(count($gs->export()) == 1);
$this->assertTrue($gs->get('a') == 'b');
}

function test_exception() {
$this->expectException();
$gs = gen_state::wrap(array('a' => 'b'));
$gs->get('b');
}

function test_default() {
$gs = gen_state::wrap(array());
$this->assertTrue($gs->get_default('b', 'default value') == 'default value');
}

function test_set() {
$gs = gen_state::wrap(array());
$self = $gs->set('a', 42);
$this->assertFalse($gs->export() == array('a' => 43));
$this->assertTrue($gs->export() == array('a' => 42));
$this->assertTrue($self === $gs);
}

function test_set_new() {
$gs = gen_state::wrap(array());
$this->assertTrue($gs->set_new('newkey', 'newvalue'));
$this->expectException();
$this->assertTrue($gs->set_new('newkey', 'newvalue'));
}

function test_replace() {
$gs = gen_state::wrap(array('a' => 'wrong value'));
$this->assertTrue($gs->replace('a', 'correct value'));

$gs2 = gen_state::wrap(array());
$this->expectException();
$gs2->replace('a', 'correct value');
}

function test_keys() {

$state = array(
'A', 'b', 'CCC', 'dé'
);

$expected_keys = array_keys($state);

$gs = gen_state::wrap($expected_keys);
$this->assertTrue($gs->keys() == $expected_keys);
}

function test_get_callback() {
$gs = gen_state::wrap(array('a' => 'exists'));

$callback = 'max';
$callback_args = array(
array(1, 2, 7, 6, 5) // max is 7
);

$this->assertTrue($gs->get_callback('a', $callback, $callback_args) == 'exists');
$this->assertTrue($gs->get_callback('b', $callback, $callback_args) == 7);

$gs2 = gen_state::wrap(array());
$this->expectException();
$gs2->replace('a', 'correct value');
}

function test_merge_new() {
$gs = gen_state::wrap(array(
'a' => 'exists_a',
'b' => 'exists_b',
'c' => 'exists_c'
));

$gs->merge_new(array(
'a' => 'replaced_a',
'd' => 'replaced_d'
));

$this->assertTrue($gs->get('a') == 'exists_a');
$this->assertTrue($gs->get('d') == 'replaced_d');
}

function test_null_value() {
$a = gen_state::wrap(array('a' => null));
$this->assertTrue(is_null($a->get('a')));

$b = gen_state::wrap(array());
$b->set('b', null);
$this->assertTrue(is_null($b->get('b')));
}

function test_has() {
$gs = gen_state::wrap(array('a' => null, 'b' => 123));
$this->assertTrue($gs->has('a'));
$this->assertTrue($gs->has('b'));
$this->assertFalse($gs->has('c'));
}

function test_append_to() {
$gs = gen_state::wrap(array(
'a' => array(1, 2, 3),
'b' => 'some string'
));
$gs->append_to('a', 4);
$this->assertEqual($gs->get('a'), array(1, 2, 3, 4));
$gs->append_to('b', '-other string');
$this->assertEqual($gs->get('b'), 'some string-other string');
$gs->append_to('a', 'val', 'key');
$this->assertEqual($gs->get('a'), array(1, 2, 3, 4, 'key' => 'val'));
}

}