View Full Version : [PAIR] Fran vs Anonimo - The Beginning
Il task consiste nel restituire un oggetto NullAudio, che implementa l'interfaccia AudioInterface, e che fa nulla, quando la creazione di un oggetto Audio fallisce.
Questo e' il test che alla fine del task deve passare:
public void testAudioCreationFailure()
{
AudioFactory audioFactory = new FailingAudioFactory();
AudioInterface audio = environment.createAudio(audioFactory);
assertTrue(audio.isNull());
}
Il test e' nel repository commentato. Non puo' passare perche' mancano tante cose all'appello:
- il metodo isNull() in AudioInterface
- la classe audioFactory()
- una versione del metodo createAudio() di environment che accetti un oggetto AudioFactory
Manca inoltre una classe NullAudio.
Partiamo con il metodo isNull(), questo e' il test in TestAudio.java:
public void setUp()
{
audio = MockAudio.create();
}
public void testIsNullNotTrueForMockAudio()
{
assertFalse(audio.isNull());
}
AnonimoVeneziano
24-01-2008, 21:19
Eccomi.
Per permettere la compilazione del test è stato aggiunto un metodo all'interfaccia AudioInterface :
boolean isNull();
Successivamente sono stati aggiunti i seguenti metodi in OpenALAudio :
public boolean isNull()
{
return false;
}
e in MockAudio :
public boolean isNull()
{
return true;
}
A questo punto il test compilava, ma falliva.
Per farlo passare è stato cambiato in MockAudio in questo modo :
public boolean isNull()
{
return false;
}
Test passato e avanti il prossimo :D
Il prossimo test richiede una classe NullAudio che sia nulla:
public void testNullAudioIsNull()
{
audio = new NullAudio();
assertTrue(audio.isNull());
}
AnonimoVeneziano
24-01-2008, 21:30
Ok, creata una classe NullAudio che implementa AudioInterface.
Eclipse ha creato automaticamente questa classe :
package it.diamonds.engine.audio;
public class NullAudio implements AudioInterface
{
public Sound createSound(String name)
{
// TODO Auto-generated method stub
return null;
}
public boolean isCreated()
{
// TODO Auto-generated method stub
return false;
}
public boolean isInitialised()
{
// TODO Auto-generated method stub
return false;
}
public boolean isMusicPlaying()
{
// TODO Auto-generated method stub
return false;
}
public boolean isNull()
{
// TODO Auto-generated method stub
return false;
}
public void playMusic()
{
// TODO Auto-generated method stub
}
public void shutDown()
{
// TODO Auto-generated method stub
}
public void stopMusic()
{
// TODO Auto-generated method stub
}
}
cambiando l'implementazione di "isNull()" in :
public boolean isNull()
{
return true;
}
Il test passa.
Ora ci serve l'AudioFactory, questo e' il test:
package it.diamonds.tests.engine;
import junit.framework.TestCase;
public class TestAudioFactory extends TestCase
{
public void testAudioFactoryCreate()
{
AudioFactory factory = new AudioFactory();
assertNotNull(factory.create());
}
}
AnonimoVeneziano
24-01-2008, 21:50
Ok
Creazione di una classe it.diamonds.engine.AudioFactory :
package it.diamonds.engine;
public class AudioFactory
{
public Object create()
{
return null;
}
}
Il test fallisce.
Cambiando in :
public Object create()
{
return 0;
}
Il test riesce
C'e' un bug in NullAudio, faccio prima a metterti il test che a spiegartelo:
package it.diamonds.tests.engine.audio;
import it.diamonds.engine.audio.AudioInterface;
import it.diamonds.engine.audio.NullAudio;
import junit.framework.TestCase;
public class TestNullAudio extends TestCase
{
public void testNullAudioIsCreated()
{
AudioInterface audio = new NullAudio();
assertTrue(audio.isCreated());
}
}
AnonimoVeneziano
24-01-2008, 22:01
Non avevo mai visto un bug così :D
Il bug è stato risolto cambiando in it.diamonds.engine.audio.NullAudio :
public boolean isCreated()
{
return false;
}
in:
public boolean isCreated()
{
return true;
}
Prossimo test:
package it.diamonds.tests.engine;
import it.diamonds.engine.AudioFactory;
import junit.framework.TestCase;
public class TestAudioFactory extends TestCase
{
public void testAudioFactoryCreate()
{
AudioFactory factory = new AudioFactory();
assertNotNull(factory.create());
}
public void testAudioFactoryCreateMockAudio()
{
AudioFactory factory = new MockAudioFactory();
assertNotNull((MockAudio) factory.create());
}
}
AnonimoVeneziano
24-01-2008, 22:21
Creata la classe it.diamonds.tests.mocks.MockAudioFactory :
public class MockAudioFactory extends AudioFactory
{
}
Da un errore di compilazione perchè la AudioFactory.create() di fatto ritorna un Integer.
Aggiungendo un override della create nella classe :
public AudioInterface create()
{
return MockAudio.create();
}
Il test riesce.
Chiudiamo il conto con AudioFactory :D
package it.diamonds.tests.engine;
import it.diamonds.engine.AudioFactory;
import it.diamonds.engine.audio.AudioInterface;
import it.diamonds.tests.mocks.MockAudio;
import it.diamonds.tests.mocks.MockAudioFactory;
import junit.framework.TestCase;
public class TestAudioFactory extends TestCase
{
public void testAudioFactoryCreate()
{
AudioFactory factory = new AudioFactory();
assertNotNull(factory.create());
}
public void testAudioFactoryCreateMockAudio()
{
AudioFactory factory = new MockAudioFactory();
assertNotNull((MockAudio) factory.create());
}
public void testAudioFactoryCreateAudioInterface()
{
AudioFactory factory = new AudioFactory();
assertNotNull((AudioInterface) factory.create());
}
}
AnonimoVeneziano
24-01-2008, 22:32
Cambiamo :
public Object create()
{
return 0;
}
in:
public AudioInterface create()
{
return new NullAudio();
}
Test passato!
In TestEnvironment.java, un test che chieda di passare un AudioFactory al metodo createAudio di Environment:
public void testAudioCreationWithFactory()
{
AudioFactory audioFactory = new AudioFactory();
assertNotNull((AudioInterface) environment.createAudio(audioFactory));
}
AnonimoVeneziano
24-01-2008, 22:39
Aggiunto il metodo in it.diamonds.Envionment :
public AudioInterface createAudio(AudioFactory factory)
{
return factory.create();
}
Ora creiamo una classe mock che ritorni un eccezione quando tenta di creare un Audio.
Questo e' il test:
public void testFailingAudioFactoryMockException()
{
try
{
AudioFactory audioFactory = new FailingAudioFactoryMock();
audioFactory.create();
fail();
}
catch (RuntimeException e)
{
}
}
AnonimoVeneziano
24-01-2008, 22:50
Creata la classe it.diamonds.tests.mocks.FailingAudioFactoryMock :
public class FailingAudioFactoryMock extends AudioFactory
{
public AudioInterface create()
{
throw new RuntimeException();
}
}
Il Deathmatch continua .... :asd:
Proviamo a dare un colpo all'ultimo test, vediamo se si riesce a far passare con un paio di righe di codice:
public void testAudioCreationFailure()
{
AudioFactory audioFactory = new FailingAudioFactoryMock();
AudioInterface audio = environment.createAudio(audioFactory);
assertTrue(audio.isNull());
}
AnonimoVeneziano
24-01-2008, 23:00
In it.diamonds.Environment la funzione createAudio(AudioFactory) è stata cambiata così :
public AudioInterface createAudio(AudioFactory factory)
{
return new NullAudio();
}
Adesso il test passa.
Questo vuol dire che il primo test di verifica che ho scritto non dava abbastanza informazioni, ci serve un altro test:
public void testAudioNotNullCreationWithFactory()
{
AudioFactory audioFactory = new MockAudioFactory();
AudioInterface audio = environment.createAudio(audioFactory);
assertFalse(audio.isNull());
}
AnonimoVeneziano
24-01-2008, 23:36
Dopo grandi ed epiche lotte intestine tra Eclipse e il repository SVN ecco le modifiche al codice :D
Metodo Environment.createAudio(AudioFactory)
public AudioInterface createAudio(AudioFactory factory)
{
try
{
audio = factory.create();
} catch (RuntimeException e)
{
audio = new NullAudio();
}
return audio;
}
Uomo 1 Macchina 0 :muro:
Finito!
Non resta che modificare createAudio() cosi':
public AudioInterface createAudio()
{
AudioFactory factory = new AudioFactory()
{
public AudioInterface create()
{
return OpenALAudio.create();
}
};
return createAudio(factory);
}
Ora basta lanciare e vedere se il tutto funziona. Se qualcosa va storto ci sara' da scrivere qualche altro test...
AnonimoVeneziano
24-01-2008, 23:59
Il problema non è risolto.
Ci si vede per il task della NullSound :D
public void testAudioCreationFailure()
{
AudioFactory audioFactory = new FailingAudioFactory();
AudioInterface audio = environment.createAudio(audioFactory);
assertTrue(audio.isNull());
}
cè bisogno di sapere che audio.isNull() == true?
Non basterebe controllare che audio sia != null e non siano lanciate eccezioni?
(anche se mi rendo conto che un metodo per sapere se l'audio è "reale" può sempre far comodo....YIANGI!!!)
ps.si potrebbe anche provare come l'oggetto, restituito da una factory che lancia eccezioni, si comporta con gli altri metodi. Per testare insomma che non lanci eccezioni lui a sua volta da altre parti, etc.
AnonimoVeneziano
25-01-2008, 12:58
cè bisogno di sapere che audio.isNull() == true?
Non basterebe controllare che audio sia != null e non siano lanciate eccezioni?
(anche se mi rendo conto che un metodo per sapere se l'audio è "reale" può sempre far comodo....YIANGI!!!)
ps.si potrebbe anche provare come l'oggetto, restituito da una factory che lancia eccezioni, si comporta con gli altri metodi. Per testare insomma che non lanci eccezioni lui a sua volta da altre parti, etc.
Lo scopo del task era proprio quello di generare una NullAudio che non facesse nulla e che venisse instanziata al posto della OpenALAudio in caso di errore di device audio :D
Facendo come dici tu (che era il mio metodo iniziale di correzione di questo problema) non ci sarebbe stato bisogno di una NullAudio e di tutte le corrispettive AudioFactory ... etc ( e della futura NullSound), ma però bisognerebbe andare a fare modifiche in GameLoop ed Environment piuttosto pesanti. Più pesanti di quelle che sono state fatte con l'introduzione di queste nuove classi (GameLoop addririttura non è stata toccata, mentre Environment ha un metodo nuovo, ma il contratto della createAudio() originale non è stato alterato ;) )
Ciao
cdimauro
26-01-2008, 05:53
Pensavo di introdurre un'interfaccia per Environment e due implementazioni specifiche, una per il codice di produzione e una per quello di test (così quest'ultima si occupava di istanziare tutti i mock necessari), ma non so se è il caso, visto che s'è intrapresa la strada delle factory...
Pensavo di introdurre un'interfaccia per Environment e due implementazioni specifiche, una per il codice di produzione e una per quello di test (così quest'ultima si occupava di istanziare tutti i mock necessari), ma non so se è il caso, visto che s'è intrapresa la strada delle factory...
io sarei piu per un environament customizzabile in creazione con i factory. Ci evitiamo un interfaccia, e se un test ha bisogno di un componente particolare(ad esempio il factory audio che spara un eccezione invece di non fare nulla) si può creare il suo env particolare. In piu viene sempre testato l'env di produzione, le uniche cose che possono cambiare sono le factory.
cdimauro
26-01-2008, 10:39
Mah. A Fran piacciono le interfacce, e personalmente non mi sono mai piaciuti particolarmente i factory.
Per maggiori informazioni: http://blogs.ugidotnet.org/Franny/archive/2007/11/27/89972.aspx :asd:
Comunque per adesso vediamo come si evolve il design coi factory. Tanto per rifattorizzare eventualmente c'è sempre tempo. :D
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.