PDA

View Full Version : Test Driven Development, Task 14.1.2 [71104 vs redcloud, GIUSTO IN RITARDO]


71104
07-04-2006, 23:39
allora, richiesta del task:
Ogni volta che una coppia di gemme viene droppata si guarda il valore del numero di Stone in Arrivo si inserisce un numero pari di Stone all'interno della griglia. L'inserimento avviene dalla prima colonna a sinistra. Ad ogni Stone inserita si scorrono le colonne verso destra. Quando si raggiunge il fondo si riparte dalla colonna più a sinistra. Durante l'inserimento la gravità è settata come "accelerata".

test list:

- Controllo della presenza di incoming stone prima della caduta di una nuova gemspair
- Riempimento con stone delle colonne da sinistra verso destra
- Controllo tra quantità stone e colonne, disposizione su più righe
- Controllo della gravità


adesso fatemi pensare al primo test, mumble... :mbe:

71104
08-04-2006, 00:13
dopo una breve spiegazione a redcloud sul TDD e sul Pair Programming, ecco il primo test:


public void testCheckIncomingStones()
{
playField.addIncomingStones(5);
assertEquals(playField.getIncomingStones(), 5);
}


si trova in TestPlayField e richiede l'aggiunta di un metodo per sapere quante incoming stones ci sono in un dato momento.

71104
08-04-2006, 01:30
redcloud ha risolto quel test aggiungendo a PlayField:

public int getIncomingStones()
{
return warningBox.getCounter();
}

come inizio di TDD non c'è male per lui :)
la prima soluzione che era venuta in mente ad entrambi esaminando il codice di playField era una variabile globale, lui invece ne ha trovata una più semplice :)

ragazzi, purtroppo devo dire che stasera abbiamo scritto pochissimo codice a causa del fatto che redcloud era al suo primo pair ma anche a causa del fatto che non esaminavo il codice da parecchio; adesso però siamo partiti e abbiamo capito come fare: da adesso andiamo molto più spediti.

per stasera facciamo solo altri due test e relative implementazioni, ma contiamo di finire entro domenica; io domani esco di sera e di pomeriggio sono a casa, se sabato pomeriggio va bene anche a redcloud (lo so, sto chiedendo qualcosa di infame ^_^) possiamo finire anche domani.

nel frattempo ecco il prossimo semplicissimo test:


public void testInsertNoStones()
{
controller.insertStones(0);
assertFalse(controller.getGrid().isGemAt(0, 0));
}


serve a testare una prima funzionalità di un ipotetico metodo insertStones che riceve in input il numero di pietre da inserire nella griglia; questo metodo dovrà essere richiamato da GridController.update() se opportuno.

redcloud
08-04-2006, 01:48
Oggi pomeriggio ci sarò :D

71104
08-04-2006, 01:51
Oggi pomeriggio ci sarò :D eh, meglio così, altrimenti non ci sarebbero state più le mie ditine :D

cmq, soluzione di redcloud all'ultimo test:


public void insertStones(int stoneNumber)
{
;
}


mi pare giusto ^^

prossimo test:

public void testInsertFirstStone()
{
controller.insertStones(1);
assertTrue(controller.getGrid().isGemAt(0, 0));
assertFalse(controller.getGrid().isGemAt(0, 1));
}


PS: redcloud, la prossima volta, cioè domani pomeriggio, ti farò un esempio concreto di triangolazione ;)

redcloud
08-04-2006, 02:06
Eeeee ormai ho trovato un passatempo produttivo! Addio ogame! :) Grazie tante 7165512 :ciapet:

71104
08-04-2006, 02:10
Eeeee ormai ho trovato un passatempo produttivo! Addio ogame! :) Grazie tante 7165512 :ciapet: :Prrr:

allora, soluzione di redcloud:

public void insertStones(int stoneNumber)
{
if(stoneNumber==0)
{
;
}
else
{
grid.insertGem(0, 0, Stone.create(DroppableColor.EMERALD));
}
}


bene bene bene: a domani la triangolazione e la consistenza del colore della pietra con quello indicato nel pattern :)
e a seguire a ruota l'inserzione delle pietre successive all'ottava.

notte a tutti

thebol
08-04-2006, 09:52
stamattina prima di procedere mi puoi conttattare su msn?(sono b0l_padawan, ho gia provato a contattarti)

devo committare una modifica grossa su gridController e voglio farla prima che continuiate a toccarla se no è un macello

thebol
08-04-2006, 10:04
la modifica era piccola sono riuscito ad arrangiarmi per i fatti miei ed ho committato. Cmq continuo lo sviluppo del pattern, se riprendete fatemi sapere.

Ufo13
08-04-2006, 10:18
dopo una breve spiegazione a redcloud sul TDD e sul Pair Programming, ecco il primo test:


public void testCheckIncomingStones()
{
playField.addIncomingStones(5);
assertEquals(playField.getIncomingStones(), 5);
}


si trova in TestPlayField e richiede l'aggiunta di un metodo per sapere quante incoming stones ci sono in un dato momento.

Potete aggiungere ancora un test su questa cosa per favore? :)

Passa anche se gli fai ritornare 5 direttamente :)

Bonfo
08-04-2006, 10:31
Quando io e RedCloud avevamo iniziato questo task Ufo aveva chiesto se era possibile non complicare Grid e GrodController.
In grid è già presente il metodo insert insertStoneInColumn()...perchè non usate e modficate quello??

SOprattutto questo metodo è accedibile direttamente da playField:

playField.getGridController().getGrid().insertStoneInColumn()


Il che vi risparmierebbe il getIncomingStones().

Pensateci se è una cosa che vi piace o no.
A me piace moooolto :D :D :D

71104
08-04-2006, 13:53
eh Bonfo, sto metodo non l'avevamo neanche notato ^^
grazie per avercelo fatto notare, il codice di Diamond Crush è doventato piuttosto vasto e quando si pensa ai test tocca pure cercare i metodi giusti in mezzo a tanti...

71104
08-04-2006, 13:55
Potete aggiungere ancora un test su questa cosa per favore? :)

Passa anche se gli fai ritornare 5 direttamente :) giustissimo, l'avevo anche fatto notare a redcloud ma non ci eravamo preoccupati di essere troppo pignoli perché si trattava di un metodo semplicissimo; l'altro test lo metterei se non fosse che forse getIncomingStones va eliminato, come suggerito da Bonfo... :)
vedremo dove ci porterà il codice.

71104
08-04-2006, 14:05
scusate, ma il metodo insertStoneInColumn perché l'avete messo visto che non lo usa nessuno...? (Eclipse non trova riferimenti)
era stato messo apposta per questo task?

71104
08-04-2006, 14:28
scusate, ma il metodo insertStoneInColumn perché l'avete messo visto che non lo usa nessuno...? (Eclipse non trova riferimenti)
era stato messo apposta per questo task? redcloud sta modificando l'implementazione di insertStones affinché utilizzi il metodo insertStoneInColumn al posto di insertGem; nel frattempo ecco il prossimo test:

public void testInsertNextStones()
{
controller.insertStones(2);
assertTrue(controller.getGrid().isGemAt(0, 0));
assertTrue(controller.getGrid().isGemAt(0, 1));
assertFalse(controller.getGrid().isGemAt(0, 2));
}

redcloud, questa volta ti tocca il for ;)

redcloud
08-04-2006, 15:21
Per superare


public void testInsertNextStones()
{
controller.insertStones(2);
assertTrue(controller.getGrid().isGemAt(0, 0));
assertTrue(controller.getGrid().isGemAt(0, 1));
assertFalse(controller.getGrid().isGemAt(0, 2));
}


ho utilizzato


public void insertStones(int stoneNumber)
{
for(int i=0; i<stoneNumber; i++)
{
grid.insertGem(0, i, Stone.create(DroppableColor.EMERALD));
}
}


nella classe GridController

71104
08-04-2006, 15:27
bene, adesso vediamo i colori:

public void testStoneColor()
{
controller.insertStones(8, pattern);
for(int i = 0; i < 8; i++) {
assertEquals(grid.getGemAt(0, i).getColor(), pattern.getDroppableColor(i));
}
}

fek
08-04-2006, 15:46
scusate, ma il metodo insertStoneInColumn perché l'avete messo visto che non lo usa nessuno...? (Eclipse non trova riferimenti)
era stato messo apposta per questo task?

Guarda, neppure ci penso, Eclipse segnala un metodo che non e' usato da nessuna parte e io lo uccido automaticamente.

Se tutti dovessimo lasciare metodi che seriviranno in futuro, il codice diventa grande il doppio. Nel repository voglio solo codice che e' usato, e che e' testato.

71104
08-04-2006, 15:46
ho spostato tutti i test di questo task in TestIncomingStones, tranne quello per getIncomingStones che si trova ancora in mezzo a quelli per PlayField.

71104
08-04-2006, 15:47
Guarda, neppure ci penso, Eclipse segnala un metodo che non e' usato da nessuna parte e io lo uccido automaticamente.

Se tutti dovessimo lasciare metodi che seriviranno in futuro, il codice diventa grande il doppio. Nel repository voglio solo codice che e' usato, e che e' testato. ok ^^
oltrettutto redcloud ha anche provato ad usarlo in insertStones, ma non è riuscito a farlo funzionare...

EDIT: lo eliminerò dopo perché la sua eliminazione comporta anche qualche correzione in alcuni test che lo usano (non per testarlo però, almeno non tutti); per ora quello che ci preme è di finire quest'altro test perché tra poco devo uscire O.o'

71104
08-04-2006, 15:58
allora, redcloud ha scritto il codice per quest'ultimo test, solo che il test fallisce a causa del fatto che il test richiede l'inserzione delle stones in tutta la prima riga, nella quale però c'è già la coppia iniziale di gemme che appaiono quando inizia il gioco.
per ora redcloud sta committando con quel test commentato, ma la cosa va sistemata e la sistemerò o stanotte all'una (lol ^^) o domani mattina.
se qualcuno sa già come sistemarla (cioè conosce già quale metodo di Grid bisogna usare per togliere la coppia iniziale) se corregge e committa col test decommentato ci fa un favore... ^^'
occhio che, come ho detto prima, adesso i test di questo task stanno tutti in TestIncomingStones.
ciao

Ufo13
08-04-2006, 16:34
Quel metodo è stato un nostro errore. Dovevamo revertare il task :)

thebol
08-04-2006, 17:30
se qualcuno sa già come sistemarla (cioè conosce già quale metodo di Grid bisogna usare per togliere la coppia iniziale) se corregge e committa col test decommentato ci fa un favore... ^^'
occhio che, come ho detto prima, adesso i test di questo task stanno tutti in TestIncomingStones.
ciao

in qualche test viene fatta questa cosa
mo lo cerco...
...
prova a vedere la setup di testGemCrushing :)

Bonfo
08-04-2006, 20:50
Il metodo insertStoneIntoColumn lo avevamomesso io e Ufo...
...lo abbiamo usato nei test relativi al task per il controllo dei frame corretti in base al numero di geme nella colonna.
Lo abbiamo messo lì perchè non c'era nessun'altro posto in cui avesse senso metterlo.
Spiegatemi perchè è sbagliato?? :mbe: :cry:

Comunque la risoluzione del problema delle geme già presenti in playField lo già affrontata ... anzi molto probabilemnte per fare il task 4 ho visto che devo modificare TestIncomingStone
Quindi ci penso io ;)

Bonfo
08-04-2006, 20:57
Scusate, ma perchè questo è diventato pubblico??

public static final int[] DEFAULT = { 1, 2, 2, 3, 3, 4, 4, 5 };


:mbe: :mbe:

E poi questo

pattern = new Pattern(new MockRandomGenerator(Pattern.DEFAULT));


A che serve ?? :wtf: :wtf:
...il RandomGenerator determina solo il valore di base per un mapping tra colorie valori del pattern.
Basta che gli mettiate la MOCK_SEQUENCE per essere sicuri che il mammping rimanga fisso quello che volete voi ;)

Bonfo
08-04-2006, 21:23
Aggiornato TestIncomingStone. :O
Il test non dà più errori ma fallisce :D

E' rimasto commentato...muovetevi a metterlo a posto se no qualcuno perde le ditine :D :D

Ufo13
09-04-2006, 00:15
Aggiornato TestIncomingStone. :O
Il test non dà più errori ma fallisce :D

E' rimasto commentato...muovetevi a metterlo a posto se no qualcuno perde le ditine :D :D

tutto via per piacere :)

Ufo13
09-04-2006, 11:49
Ho fatto un po' di refactoring nei vostri test.

Comunque ha ragione Bonfo, questa:


pattern = new Pattern(new MockRandomGenerator(Pattern.DEFAULT));


è concettualmente errata. Confonde chi legge il test facendogli credere che il pattern sia una sequenza di random...

71104
09-04-2006, 12:12
e scusa, che c'era di sbagliato...? il costruttore di Pattern vuole una RandomInterface, io devo poter controllare quei valori nel test, quindi gli ho passato il mock... e al mock gli ho passato la sequenza che voglio io, che è quella predefinita di Pattern...

non è il test che confonde chi legge facendogli credere che il Pattern sia una sequenza di random: è il costruttore di Pattern che lo fa!! :D

fek
09-04-2006, 12:18
e scusa, che c'era di sbagliato...? il costruttore di Pattern vuole una RandomInterface, io devo poter controllare quei valori nel test, quindi gli ho passato il mock... e al mock gli ho passato la sequenza che voglio io, che è quella predefinita di Pattern...

non è il test che confonde chi legge facendogli credere che il Pattern sia una sequenza di random: è il costruttore di Pattern che lo fa!! :D

Quindi va rifattorizzato il costruttore di pattern. Non vedo il motivo di passargli una sequenza random. Avevamo pensato con Jocchan di passare una sequenza di numeri tipo:

1122334455

E poi a ogni numero viene sostituito un colore random e quella e' la sequenza finale.

Ufo13
09-04-2006, 12:22
ce la fate a finire per stasera? :)

Bonfo
09-04-2006, 12:25
Probabilmente hai ragione... :(

Quel costruttore è stato fatto così per poter controllare che un test non fallisca random.

Bisogna pensare ad un costruttore più adatto....forse invece di passargli un RandomGenerator è sufficente passargli un "mappingSeed".
Però poi il compito di variare il mapping valore->colore diventà responsabilità di qualcun'altro...cosa che mi sembra non si volesse ...

....mmmmhhh...:wtf:

Comunqe per capire cosa c'è di sbagliato leggi il mio post di prima ;)


EDIT: ricordati di rimettere DEFAULT privato in pattern..altrimneti lo faccio io :Prrr:

Ufo13
09-04-2006, 12:26
visto che usi soltanto un numero nell'estrazione random potresti passare un solo intero nel costruttore...

71104
09-04-2006, 12:27
Quindi va rifattorizzato il costruttore di pattern. Non vedo il motivo di passargli una sequenza random. Avevamo pensato con Jocchan di passare una sequenza di numeri tipo:

1122334455

E poi a ogni numero viene sostituito un colore random e quella e' la sequenza finale. ehm, no fek era colpa mia: Federico mi ha appena fatto notare su MSN che in realtà il generatore di numeri random non viene usato per generare tutta la sequenza del pattern, ma solo un numero intero "base" che viene poi sommato ai colori del pattern predefinito per ottenere il pattern finale; in altre parole il pattern finale risulta sfasato rispetto a quello di default di un certo numero intero casuale. basta che al costruttore di MockRandomGeneratore gli passo 0... ;)

Bonfo
09-04-2006, 12:29
Quindi va rifattorizzato il costruttore di pattern. Non vedo il motivo di passargli una sequenza random. Avevamo pensato con Jocchan di passare una sequenza di numeri tipo:

1122334455

E poi a ogni numero viene sostituito un colore random e quella e' la sequenza finale.

Il pattern lo ho fatto io....e non si era capito bene come era stato pensato.
L'ho pure chiesto ma nessuno mi ha detto che avevo capito male. :Prrr:

Ripeto: all'inizio il costruttore era Pattern().
E' stato modficato per evitare che un test fallise random... il randomGeneratoer prima era privato e mi serve per attribuire il mapping valore->in modo casuale.

Appena mi date il via lo modifico per fargli fare quello che ha detto fek :D

Ufo13
09-04-2006, 12:29
.

71104
09-04-2006, 12:30
ce la fate a finire per stasera? :) dobbiamo finire per stasera!! ecco il prossimo test (si ringrazia Bonfo per la funzione stopAndRemoveGemsPair :D):

public void testStoneColors()
{
controller.insertStones(8, pattern);
for(int i = 0; i < 8; i++) {
assertEquals(grid.getGemAt(0, i).getColor(), pattern.getDroppableColor(i));
}
}

redcloud è andato a pranzo, quando torna implementa il test e poi via col successivo.

PS: il motivo percui il primo test prima dava problemi era la coppia iniziale di gemme già inserita nella griglia che adesso viene eliminata tramite stopAndRemoveGemsPair.

Bonfo
09-04-2006, 12:30
visto che usi soltanto un numero nell'estrazione random potresti passare un solo intero nel costruttore...

Ok...modifico ;)

71104
09-04-2006, 12:33
No mi sa che non hai capito... Il pattern è sempre uguale, non viene sfasato... Cambia soltanto l'assegnazione COLORE-NUMERO :) e non si chiama pattern...? :mbe:

Ufo13
09-04-2006, 12:41
Vero, c'è un'ambiguità di termini :)

fek
09-04-2006, 13:12
Il pattern lo ho fatto io....e non si era capito bene come era stato pensato.
L'ho pure chiesto ma nessuno mi ha detto che avevo capito male. :Prrr:

Ripeto: all'inizio il costruttore era Pattern().
E' stato modficato per evitare che un test fallise random... il randomGeneratoer prima era privato e mi serve per attribuire il mapping valore->in modo casuale.

Appena mi date il via lo modifico per fargli fare quello che ha detto fek :D

Male, colpa nostra che non ti abbiamo risolto il dubbio. La prossima volta sii piu' insistente e svegliaci ;)

Bonfo
09-04-2006, 14:15
Male, colpa nostra che non ti abbiamo risolto il dubbio. La prossima volta sii piu' insistente e svegliaci ;)

Allora modifico in modo che il costruttore accetti un array di interi??
Ovviamente oltre all'index??

Pongo all'attenzio questo post :(
http://www.hwupgrade.it/forum/showpost.php?p=11948113&postcount=43

fek
09-04-2006, 14:22
Si'

Ufo13
09-04-2006, 14:24
secondo me ora come ora è YAGNI..

Bonfo
09-04-2006, 14:26
Caspitaccia. :doh:
Sto uscendo....
...verso le 17:30 dovrei essere a casa.

Appena torno mi metto al lavoro ;)

redcloud
09-04-2006, 14:27
dobbiamo finire per stasera!! ecco il prossimo test (si ringrazia Bonfo per la funzione stopAndRemoveGemsPair :D):

public void testStoneColors()
{
controller.insertStones(8, pattern);
for(int i = 0; i < 8; i++) {
assertEquals(grid.getGemAt(0, i).getColor(), pattern.getDroppableColor(i));
}
}

redcloud è andato a pranzo, quando torna implementa il test e poi via col successivo.

PS: il motivo percui il primo test prima dava problemi era la coppia iniziale di gemme già inserita nella griglia che adesso viene eliminata tramite stopAndRemoveGemsPair.
Ecco la soluzione:
public void insertStones(int stoneNumber, Pattern pattern)
{
for(int i=0; i<stoneNumber; i++)
{
grid.insertGem(0, i, Stone.create(pattern.getDroppableColor(i)));
}
}

71104
09-04-2006, 15:41
EDIT: così non ne veniamo a capo, era un test di livello troppo alto; bisogna a gire a livello più basso.

71104
09-04-2006, 16:38
va evidenziato un problema: non è possibile testare il cambiamento di stato del grid controller a meno di non usare RTTI, che però è orribile; tocca aggiungere un metodo astratto nell'interfaccia GridControllerState e poi le relative implementazioni che permetteranno di distinguere istanze di classi diverse; secondo me è l'unico modo per testare il cambiamento di stato (che finora non è testato in nessun caso). ora chiederò consiglio a Ufo13...

71104
09-04-2006, 17:13
il design di "state pattern" che è saltato fuori di recente per il controller ci ha aperto qualche problema; per ora (dopo una consultazione con Ufo13) abbiamo deciso di continuare creando un nuovo state per il controller atto a gestire la caduta delle pietre; successivamente faremo i test per integrarlo in GridController.

ecco il nuovo test case:

public class TestStoneFallState extends TestCase
{
private MockTimer timer;

private StoneFallState state;

private GameLoop loop;

private PlayField field;
private GridController controller;

public void setUp()
{
timer = new MockTimer();
state = new StoneFallState();
loop = GameLoop.createForTesting();
field = loop.getPlayFieldOne();
controller = field.getGridController();
}

public void testSameState()
{
assertSame(state, state.update(timer, controller));
}

}

e in futuro penso che toccherà testare anche gli altri states: secondo me la loro funzionalità è testata a un livello troppo alto e indiretto: o semplifichiamo il meccanismo togliendo questo design (ma andando così a complicare GridController di molto) oppure facciamo dei test più diretti; e i test per gli altri states sicuramente avranno molto in comune con questa TestStoneFallState, quindi penso che faremo precisamente come è stato fatto con GridTestCase. e le sue derivate.

71104
09-04-2006, 17:14
primo banale test: di norma lo "stone fall state" (come qualsiasi altro state) ha una certa durata, perciò finché lo state non finisce lo state continua a ritornare this.

public void testSameState()
{
assertSame(state, state.update(timer, controller));
}

Bonfo
09-04-2006, 17:31
Quando fate il commit mettete dei commenti un minimo più esplicativi :asd: :asd:

71104
09-04-2006, 17:35
ehm, questo test però non fallisce a causa dello stub automatico messo da Eclipse :D

ok, allora passiamo al successivo; proviamo ad inserire una pietra e a vedere se lo state la inserisce per davvero nella griglia :p

public void testStonesAdded()
{
state.setIncomingStones(1);
state.update(timer, controller);
assertTrue(grid.getGemAt(0, 0).getType().isStone());
}

Ufo13
09-04-2006, 17:37
I commenti nei Commit devono essere:

Nick_sul_forum: breve_riassunto


un esempio

Ufo13: Refactoring di Grid, eliminati due metodi mai utilizzati.

71104
09-04-2006, 17:55
soluzione dell'ultimo test:

public class StoneFallState implements GridControllerState
{
public GridControllerState update(TimerInterface timer, GridController gridController)
{
gridController.insertStones(1, new Pattern((new RandomGenerator()).extract(8)));
return this;
}

public void setIncomingStones(int stonesNumber)
{
;
}

}

hum, no, decisamente non è quello che volevo :D

proviamo a mettere questo e vediamo che succede:

public void testTwoStonesAdded()
{
state.setIncomingStones(2);
state.update(timer, controller);
assertTrue(grid.getGemAt(0, 0).getType().isStone());
assertTrue(grid.getGemAt(0, 1).getType().isStone());
}

redcloud
09-04-2006, 20:07
Soluzione:
public class StoneFallState implements GridControllerState
{
private int incomingStones;

public GridControllerState update(TimerInterface timer, GridController gridController)
{
gridController.insertStones(this.incomingStones, new Pattern((new RandomGenerator()).extract(8)));
return this;
}

public void setIncomingStones(int stonesNumber)
{
this.incomingStones = stonesNumber;
}

}

thebol
09-04-2006, 20:09
il design di "state pattern" che è saltato fuori di recente per il controller ci ha aperto qualche problema; per ora (dopo una consultazione con Ufo13) abbiamo deciso di continuare creando un nuovo state per il controller atto a gestire la caduta delle pietre; successivamente faremo i test per integrarlo in GridController.



lo state pattern è nato 3 giorni fa, estraendo i vari stati da gridController. gli stati non sono testati perche non ne ho avuto il tempo, e fare un commit unico (refactoring + test specifici) sarebbe stato incasinato(avrei rischiato di fare tutto il lavoro per poi trovarmi troppo out of sync col cvs). La correttezza del giro e garantita dai test esistenti(che non sono stati minimamente toccati), quella delle singole classi è da fare.


ps.lo stesso problema, ce l'hanno le classi action, tranne la stoneUpdateblabla..

Ufo13
09-04-2006, 20:13
lo state pattern è nato 3 giorni fa, estraendo i vari stati da gridController. gli stati non sono testati perche non ne ho avuto il tempo, e fare un commit unico (refactoring + test specifici) sarebbe stato incasinato(avrei rischiato di fare tutto il lavoro per poi trovarmi troppo out of sync col cvs). La correttezza del giro e garantita dai test esistenti(che non sono stati minimamente toccati), quella delle singole classi è da fare.


ps.lo stesso problema, ce l'hanno le classi action, tranne la stoneUpdateblabla..

Pensi di riuscire a testarle prima della release? Sarebbe molto bello portare in release il tutto ben testato :)

thebol
09-04-2006, 20:20
Pensi di riuscire a testarle prima della release? Sarebbe molto bello portare in release il tutto ben testato :)
in una settimana potrei farcela, ma dipende dal tempo che avrò a disposizione..

71104
09-04-2006, 20:42
Soluzione: [...] sia lodata la triangolazione :ave: :D

ora questo:

public void testAddedOnce()
{
state.setIncomingStones(1);
state.update(timer, controller);
try
{
state.update(timer, controller);
}
catch(IllegalArgumentException e)
{
fail("StoneFallState adds stones more than once");
}
}

non vorremmo inserirne troppe... ;)

71104
09-04-2006, 20:57
modifiche di redcloud:

public GridControllerState update(TimerInterface timer, GridController gridController)
{
gridController.insertStones(incomingStones, new Pattern((new RandomGenerator()).extract(8)));
incomingStones = 0;
return this;
}

ora ci cimentiamo in qualcosa di più complicato:

public void testStateChange()
{
state.setIncomingStones(1);
state.update(timer, controller);
Droppable stone = grid.getGemAt(0, 0);
GridControllerState newState = state;
while(stone.isFalling())
{
newState = state.update(timer, controller);
timer.advance(10);
}
assertNotSame(state, newState);
}

quando le pietre finiscono di cadere lo stato deve cambiare... :)

71104
09-04-2006, 22:16
ho dovuto modificare il test: quello di prima non andava bene e la nuova versione è decisamente più chiara:

public void testStateChange()
{
state.setIncomingStones(1);
state.update(timer, controller);
Droppable stone = grid.getGemAt(0, 0);
stone.drop();
assertNotSame(state, state.update(timer, controller));
}

e queste sono le modifiche necessarie a farlo passare:

public GridControllerState update(TimerInterface timer, GridController gridController)
{
gridController.insertStones(incomingStones, new Pattern((new RandomGenerator()).extract(8)));
if(0 != incomingStones)
{
incomingStones = 0;
stone = gridController.getGrid().getGemAt(0, 0);
}
if(null != stone)
{
if(stone.isNotFalling())
{
return new GemsPairOnControllState(config);
}
}
return this;
}

l'avevo detto che era più complicato ^^

ok, ma per quello che vogliamo fare noi non basta, serve anche questo:

public void testStateChangeAfterEveryStoneHasDropped()
{
state.setIncomingStones(2);
state.update(timer, controller);
Droppable stone1 = grid.getGemAt(0, 0);
Droppable stone2 = grid.getGemAt(0, 1);
stone1.drop();
assertSame(state, state.update(timer, controller));
stone2.drop();
assertNotSame(state, state.update(timer, controller));
}

e il problema è che la mia controparte se n'è andata, dice che torna tra un paio d'ore :(
spero che Ufo13 mi dia il permesso di fare qualcosa da solo...

71104
09-04-2006, 22:44
spero che Ufo13 mi dia il permesso di fare qualcosa da solo... permesso accordato; ed ecco come ho risolto quel test:

public GridControllerState update(TimerInterface timer, GridController gridController)
{
stones.addAll(gridController.insertStones(incomingStones, new Pattern((new RandomGenerator()).extract(8))));
incomingStones = 0;
if(0 != stones.size())
{
boolean allDropped = true;
for(int i = 0; allDropped && (i < stones.size()); i++)
{
allDropped &= stones.get(i).isNotFalling();
}
if(allDropped)
{
return new GemsPairOnControllState(config);
}
}
return this;
}

ma si è reso necessario un refactoring a insertStones, che come avrete intuito ritorna in un array le pietre inserite; e questo refactoring andrebbe decisamente testato; già già...

71104
09-04-2006, 23:12
ma si è reso necessario un refactoring a insertStones, che come avrete intuito ritorna in un array le pietre inserite; e questo refactoring andrebbe decisamente testato; già già... detto fatto ^^

public class TestIncomingStones extends GridTestCase
{
.
.
.
public void testReturnedArray()
{
assertEquals(6, controller.insertStones(6, pattern).size());
}

}

e adesso un piccolo aggiornamento ai test, richiestomi da Ufo13...

71104
09-04-2006, 23:52
e adesso un piccolo aggiornamento ai test, richiestomi da Ufo13... ecco qua, dopo un'approfondita discussione di OOP e design, abbiamo deciso di fare una cosa del genere:

public void testCurrentStateWrongName()
{
assertFalse(state.isCurrentState("asdasdasd"));
}

public void testCurrentStateRightName()
{
assertTrue(state.isCurrentState("StoneFall"));
}

questi nuovi metodi isCurrentState serviranno per ora solamente nei test per testare se un'oggetto GridControllerState è uno StoneFallState o un CrushState o altro.

per evitare di ripetermi dico solo come ho implementato in StoneFallState:

public boolean isCurrentState(String stateTestName)
{
return stateTestName.equals("StoneFall");
}

Bonfo
10-04-2006, 00:08
Attenzione


public Vector<Stone> insertStones(int stoneNumber, Pattern pattern)
{
Vector<Stone> insertedStones = new Vector<Stone>();
for(int i = 0; i < stoneNumber; i++)
{
Stone stone = Stone.create(pattern.getDroppableColor(i));
grid.insertGem(0, i, stone);
insertedStones.add(stone);
}
return insertedStones;
}


Manca il test che controlli che il parametro passato a getDroppableColor() sia modulo 8 :D

EDIT: ... e poi perchè usi un vector invece di un arrayList??

71104
10-04-2006, 01:43
Attenzione


public Vector<Stone> insertStones(int stoneNumber, Pattern pattern)
{
Vector<Stone> insertedStones = new Vector<Stone>();
for(int i = 0; i < stoneNumber; i++)
{
Stone stone = Stone.create(pattern.getDroppableColor(i));
grid.insertGem(0, i, stone);
insertedStones.add(stone);
}
return insertedStones;
}


Manca il test che controlli che il parametro passato a getDroppableColor() sia modulo 8 :D

EDIT: ... e poi perchè usi un vector invece di un arrayList??
per il modulo 8 aveva in mente un altro design: il parametro stoneNumber è sempre minore di 8 perché la funzione insertStones si occupa di inserire le pietre in una sola riga; sarà poi lo StoneFallState a gestire l'inserzione delle pietre su più righe (bisogna fare così per forza perché per inserire nelle righe successive bisogna aspettare che quelle della riga precedente siano scese di una riga e abbiano fatto spazio).
poi per il Vector non so, qual è la differenza tra Vector e ArrayList? a me sembrano uguali...

thebol
10-04-2006, 06:48
per il modulo 8 aveva in mente un altro design: il parametro stoneNumber è sempre minore di 8 perché la funzione insertStones si occupa di inserire le pietre in una sola riga; sarà poi lo StoneFallState a gestire l'inserzione delle pietre su più righe (bisogna fare così per forza perché per inserire nelle righe successive bisogna aspettare che quelle della riga precedente siano scese di una riga e abbiano fatto spazio).
poi per il Vector non so, qual è la differenza tra Vector e ArrayList? a me sembrano uguali...

vector è sincronizzato(e piu lento), arrayList e un oggetto che rappresente un array(organizzato percio a lista)

71104
10-04-2006, 07:24
vector è sincronizzato(e piu lento), arrayList e un oggetto che rappresente un array(organizzato percio a lista) ah ok, allora adesso lo cambio con ArrayList, che la sincronizzazione non ci serve.
thebol, tanto che ci sei, oggi fatti assolutamente vivo su MSN, specie se vedi Ufo13 online!! ^^
se hai tempo è importante che ci aiuti per finire questo task: ci serve di sapere come fare un certo test.

thebol
10-04-2006, 07:31
ah ok, allora adesso lo cambio con ArrayList, che la sincronizzazione non ci serve.
thebol, tanto che ci sei, oggi fatti assolutamente vivo su MSN, specie se vedi Ufo13 online!! ^^
se hai tempo è importante che ci aiuti per finire questo task: ci serve di sapere come fare un certo test.
mi trovi dopo le 18:30

71104
10-04-2006, 08:40
@Ufo13: sono riuscito a trovare la maniera indolore di portare avanti il task!! :)
thebol, servi ancora ma non sei più strettamente necessario per oggi ^^

spiegazione per tutto il forum: ciò che dovevo fare era integrare il nuovo StoneFallState nello state pattern, ovvero fare in modo che lo stato successivo a CrushState non fosse più WaitStateBlahBlahBlah bensì StoneFallState; poi il successivo a StoneFallState ovviamente è WaitStateBlahBlahBlah.

per fare ciò bisognava fare il refactoring di una certa linea di codice, ovvero il return value di CrushState.update; quando si fa un refactoring (ovvero quando non si aggiunge ne' si rimuove codice, ma si modifica codice esistente) non bisogna ne' aggiungere ne' rimuovere test, bisogna solo controllare che nessuno fallisca dopo il refactoring.

ufficialmente il codice della classe CrushState è testato dai test di TestGridController e da altri test, ma in realtà penso che siamo tutti d'accordo che gli state sono testati a un livello troppo alto: il meccanismo che gira durante l'esecuzione dei test di TestGridController è troppo grosso, va sicuramente testato più in dettaglio (o alternativamente ripeto, possiamo anche semplificare tutto togliendo quest'affare, ma andremmo a complicare parecchio la classe GridController).

ad ogni modo comunque finché thebol non sistema i test per lo state pattern il mio scopo in questo refactoring era solo di far passare tutti i test esistenti; ieri sera modificando questa linea

return new WaitStateBeforeNewGemsPair(config).update(timer, gridController);

con questa

return new StoneFallState(config);

fallivano numerosi test e non ho potuto refattorizzare; stamattina mi sono accorto che invece così funziona:

return new StoneFallState(config).update(timer, gridController);

e mi sembra anche più logico in effetti :)

ergo, si continua così da dove eravamo rimasti ieri sera.

PS: il TDD non è per deboli di cuore :|

71104
10-04-2006, 08:58
detto questo mi rendo conto che thebol mi serve di nuovo perché non riesco a fare il test successivo :|

fek
10-04-2006, 09:35
Quando hai finito il task mi puoi fare un elenco di che cosa vi ha fatto perdere piu' tempo e ve lo ha fatto ritardare?

Mi riferisco sia all'organizzazione del lavoro, sia ad eventuali problemi sul codice.

Ufo13
10-04-2006, 10:44
Il problema principale è che GridController già prima era diventato una cosa assura. Lo state pattern ha migliorato molto il codice ma sono da rifattorizzare proprio gli state al loro interno.

Vedo cosa posso fare appena finisce il task :)

thebol
10-04-2006, 18:48
Il problema principale è che GridController già prima era diventato una cosa assura. Lo state pattern ha migliorato molto il codice ma sono da rifattorizzare proprio gli state al loro interno.

Vedo cosa posso fare appena finisce il task :)
sto lavorando proprio su questo(oggi a lavoro ho buttato giu un workflow, ma devo risolvere un problema).

e anche per questo che non ho dato massima priorità ai test(che sarebbero stati su una classe molto grossa).

cmq per ora consiglio di testare a livello di gridController.update(come prima) e separatamente gli state nuovi. Per quelli vecchi ci sto guardando :)

fek
11-04-2006, 10:03
71104: refactoring: passato codice da GridController a StoneFallState; TDD in forma pura.

Quanto mi piace 71104 quando fa cosi' :D

thebol, a meno che tu non stia facendo uno spike, i test hanno sempre massima priorita'.

71104
11-04-2006, 12:37
71104: refactoring: passato codice da GridController a StoneFallState; TDD in forma pura.

Quanto mi piace 71104 quando fa cosi' :D

thebol, a meno che tu non stia facendo uno spike, i test hanno sempre massima priorita'. aspetta un attimo che quando ho tempo ci apro un thread su quella dicitura "TDD in forma pura": non era uno scherzo, ho fatto veramente un esperimento di TDD PURO... :D
la classe StoneFallState è stata scritta una o due righe per volta! (escludendo ovviamente le righe occupate dalle parentesi graffe)

71104
11-04-2006, 12:48
Quando hai finito il task mi puoi fare un elenco di che cosa vi ha fatto perdere piu' tempo e ve lo ha fatto ritardare?

Mi riferisco sia all'organizzazione del lavoro, sia ad eventuali problemi sul codice. allora, a parte che manca ancora da sistemare qualcosa e che il task non è del tutto finito, comunque ciò che l'ha reso così lungo sono state principalmente tre cose:

1) il task di per se' è stato sottovalutato quando è stato formulato; in realtà era molto complesso, basti notare che per questo task ho dovuto scrivere in tutto 19 test (controlla tu stesso: sono quelli di TestStoneFallState, l'ultimo di TestGridController, e gli ultimi di TestIncomingStones) e ancora non sono finiti;

2) redcloud era al suo primo pair: gli ho dovuto spiegare come si lavora in Test Driven Development e in Pair Programming; e poi succede sempre che le persone alle prime armi con queste tecniche siano più lente: ti ricordi quanto ci abbiamo messo io e te quando abbiamo lavorato al mio primo pair? sono sicuro che se lo rifacessimo adesso ci metteremmo 10 minuti, in fondo si trattava solo di gestire una matrice e poche altre cosette;

3) codice non direttamente testato: come ho evidenziato precedentemente, tutto il meccanismo dello state pattern in teoria sarebbe testato, ma lo è molto indirettamente: se escludiamo le due test case aggiunte da me (TestStoneFallState e TestCrushState) gli unici test che provocano qualche lavoro da parte di qualche classe di state sono quelli di GridController; nessun test, a parte quelli di quei due test case, crea direttamente le classi degli state per effettuare dei test su di esse; inoltre, siccome lo StoneFallState l'ho creato io, quello è l'unico veramente testato: il CrushState nel suo test case ha solamente un paio di test basilari, ma quelli veri ancora mancano. thebol (o meglio le sue ditine :D) si stanno dando da fare per rimediare alla situazione ^^ (dopo che ho finito e dopo che ho postato quel thread che dicevo sul TDD gli darò una mano anche io).

fek
11-04-2006, 13:00
Perfetto, grazie del report :)

Mi interessa capire di preciso che cosa ci impedisce di andare piu' veloci nei nostri task. Direi mancanza di test, inserimento di nuovi elementi e il loro training (inevitabile), non perfetta valutazione del task.

71104
11-04-2006, 14:07
i crash che abbiamo attualmente sono dovuti in parte alla gestione non completa di un numero di incoming stones maggiore di 8, in parte a OpenAL non so per quale motivo; i crash di OpenAL penso che vadano indagati col debugger, non so se sono legati alle stones. sto andando avanti col task (ho aggiunto altri 4 test e relative implementazioni) ma adesso devo proprio scappare, finirò stasera. nel frattempo ragazzi, provate a vedere se potete continuare con gli altri task della storia, penso che si possano fare anche senza la gestione completa delle stones in numero maggiore di 8.

Bonfo
11-04-2006, 14:11
Manca quelo che io e Ufo abbiamo fatto nel ciclo scorso:

public void insertStoneIntoColumn(Droppable stone, int column)
{
stone.setCurrentFrame(STONES_FRAMES_BASED_ON_ROW[getHeightOfColumn(column)]);
}

Ovvero l'inserimento delle stone con l frame giusto.

Mi occpuo della modifica ;)

EDIT: ritiro subito l'ultima cosa detta.
Ho visto ora lo StonesFallState...non è poi così facile modificare i test...quindi mi sa che aspetto 71104 per vedere se riusciamo a farlo insieme ;)

Bonfo
11-04-2006, 14:18
Scusate, ma in gridController invece di:

public void insertStones(ArrayList<Droppable> stones)

non sarebbe meglio un:

public void insertStones(ArrayList<Stone> stones)



:mbe: :mbe:

71104
11-04-2006, 15:20
i crash che abbiamo attualmente sono dovuti in parte alla gestione non completa di un numero di incoming stones maggiore di 8, in parte a OpenAL non so per quale motivo; i crash di OpenAL penso che vadano indagati col debugger, non so se sono legati alle stones. sto andando avanti col task (ho aggiunto altri 4 test e relative implementazioni) ma adesso devo proprio scappare, finirò stasera. nel frattempo ragazzi, provate a vedere se potete continuare con gli altri task della storia, penso che si possano fare anche senza la gestione completa delle stones in numero maggiore di 8. cambio di programma: ci lavoro adesso :D

71104
11-04-2006, 15:20
Manca quelo che io e Ufo abbiamo fatto nel ciclo scorso:

public void insertStoneIntoColumn(Droppable stone, int column)
{
stone.setCurrentFrame(STONES_FRAMES_BASED_ON_ROW[getHeightOfColumn(column)]);
}

Ovvero l'inserimento delle stone con l frame giusto.

Mi occpuo della modifica ;)

EDIT: ritiro subito l'ultima cosa detta.
Ho visto ora lo StonesFallState...non è poi così facile modificare i test...quindi mi sa che aspetto 71104 per vedere se riusciamo a farlo insieme ;) non capisco a cosa serva, dov'è che lo richiede il task? casomai contattami su MSN.

71104
11-04-2006, 15:22
Scusate, ma in gridController invece di:

public void insertStones(ArrayList<Droppable> stones)

non sarebbe meglio un:

public void insertStones(ArrayList<Stone> stones)



:mbe: :mbe: inizialmente infatti era così, poi da qualche parte nel TDD sono stato costretto a mettere Droppable per non ricordo quale motivo; ricordo che se non l'avessi fatto sarei stato costretto a fare un cast da Droppable a Stone, il che è orribile oltre che anti-OOP ;)

Bonfo
11-04-2006, 15:29
non capisco a cosa serva, dov'è che lo richiede il task? casomai contattami su MSN.

http://www.hwupgrade.it/forum/showpost.php?p=11718792&postcount=2


13.1.2: Ufo13 + Bonfo: completato
Cambiare il codice che crea le stone in modo che il frame da mostrare durante la
caduta sia dipendente dalla riga in cui è previsto che la pietra andra a collidere.
Per sapere quale frame usare seguite la tabella:
Riga Frame
13-12 2
11-10 3
9-7 4
6-4 5
3-0 6

thebol
11-04-2006, 17:13
71104: refactoring: passato codice da GridController a StoneFallState; TDD in forma pura.

Quanto mi piace 71104 quando fa cosi' :D

thebol, a meno che tu non stia facendo uno spike, i test hanno sempre massima priorita'.
il problema è testare un mostro di classe. gridController update e stata testata passo passo dalla sua creazione e i test sono stati incrementali. Io mi sono ritrovato con una classe crushState molto complicata, preferisco fidarmi dei test precedenti su gridController, semplificarla e dividerla in piu stati, e poi testarli singolarmente. Rifarla da capo nn se ne parla, visto che devo rispettare i vincoli dei test su gridController.update. Certo avrei potuto prendere tutti i test su gridController update e replicarli, ma sarebbe stato un bagno di sangue(gridController di update e usata circa 100 volte nei test...).

Altre idee per fare questo refactoring in puro tdd non le ho trovate..

fek
11-04-2006, 18:31
il problema è testare un mostro di classe. gridController update e stata testata passo passo dalla sua creazione e i test sono stati incrementali. Io mi sono ritrovato con una classe crushState molto complicata, preferisco fidarmi dei test precedenti su gridController, semplificarla e dividerla in piu stati, e poi testarli singolarmente. Rifarla da capo nn se ne parla, visto che devo rispettare i vincoli dei test su gridController.update. Certo avrei potuto prendere tutti i test su gridController update e replicarli, ma sarebbe stato un bagno di sangue(gridController di update e usata circa 100 volte nei test...).

Altre idee per fare questo refactoring in puro tdd non le ho trovate..

Se stai facendo un refactoring allora il discorso e' diverso e la strada che stai seguendo va bene :)

Soprattutto il dividere il piu' possibile ogni classe e poi cercare di testarla individualmente.