14. Unit testing In computer programming, unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. Ideally, each test case is independent from the others: substitutes like method stubs, mock objects, fakes and test harnesses can be used to assist testing a module in isolation.
15. Unit testing In computer programming, unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. Ideally, each test case is independent from the others: substitutes like method stubs, mock objects, fakes and test harnesses can be used to assist testing a module in isolation.
16. Unit testing In computer programming, unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. Ideally, each test case is independent from the others: substitutes like method stubs, mock objects, fakes and test harnesses can be used to assist testing a module in isolation.
17. Unit testing In computer programming, unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. Ideally, each test case is independent from the others: substitutes like method stubs, mock objects, fakes and test harnesses can be used to assist testing a module in isolation .
18. Scusa #1 “Non ho tempo per scrivere i test” oppure “Potrei lavorare ad altre feature nel frattempo”
21. Funziona Durante le operazioni di debug il codice testato viene eliminato velocemente. Non sarà necessario perdere tempo “ per farlo funzionare ” dato che i test garantiscono il suo funzionamento sin dall'inizio.
35. Può essere ma... Invece che scriverli tutti alla fine basta fare in modo di scriverli prima di implementare la funzionalità (TDD). Il passaggio da scrittura del test a scrittura della feature renderà tutto più divertente.
57. All'interno dei metodi di test, i metodi di asserzione come assertEquals() vengono utilizzati per verificare che un certo valore corrisponda al valore atteso.
58. Assertions – Le più comuni AssertTrue/AssertFalse Check the input to verify it equals true/false AssertEquals Check the result against another input for a match AssertGreaterThan Check the result to see if it’s larger than a value AssertContains Check that the input contains a certain value AssertType Check that a variable is of a certain type AssertNull Check that a variable is null AssertFileExists Verify that a file exists AssertRegExp Check the input against a regular expression
59. Fixtures Una delle cose più dispendiose nella scrittura dei test è la parte relativa al codice per impostare l'ambiente e partire da uno stato conosciuto e per poi tornarci alla fine del test. Lo stato conosciuto è chiamato fixture .
60. setUp() Il metodo setUp() viene invocato prima dell'esecuzione del test. Permette impostare lo stato conosciuto necessario al test.
61. tearDown() Al termine dell'esecuzione del test viene invocato il metodo tearDown() . Si occupa delle pulizie.
62. Doubles “ Sometimes it is just plain hard to test the system under test (SUT) because it depends on other components that cannot be used in the test environment. This could be because they aren't available, they will not return the results needed for the test or because executing them would have undesirable side effects. In other cases, our test strategy requires us to have more control or visibility of the internal behavior of the SUT. When we are writing a test in which we cannot (or chose not to) use a real depended-on component (DOC), we can replace it with a Test Double. The Test Double doesn't have to behave exactly like the real DOC; it merely has to provide the same API as the real one so that the SUT thinks it is the real one!” --Gerard Meszaros
63. Stub Oggetto appositamente configurato per restituire valori predefiniti. Rimpiazza un oggetto reale dal quale dipende is SUT. Permette di avere il controllo sugli input indiretti del SUT.
64. Stub - esempio <?php class SomeClass { public function doSomething() { // Do something. } } ?>
65. Stub - esempio <?php require_once 'SomeClass.php'; class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { // Create a stub for the SomeClass class. $stub = $this->getMock('SomeClass'); // Configure the stub. $stub->expects($this->any()) ->method('doSomething') ->will($this->returnValue('foo')); // Calling $stub->doSomething() will now return // 'foo'. $this->assertEquals('foo', $stub->doSomething()); } } ?>
66. Mock Oggetto appositamente configurato per verificare delle aspettative, come per esempio la chiamata di un metodo specifico. Punto di osservazione utilizzato per verificare gli output indiretti del SUT mentre è in esecuzione.
67. Mock - esempio <?php class Subject { protected $observers = array(); public function attach(Observer $observer) { $this->observers[] = $observer; } public function doSomething() { // Do something. // ... // Notify observers that we did something. $this->notify('something'); } protected function notify($argument) { foreach ($this->observers as $observer) { $observer->update($argument); } } // Other methods. }
68. Mock - esempio class Observer { public function update($argument) { // Do something. } public function reportError($errorCode, $errorMessage, Subject $subject) { // Do something } // Other methods. } ?>
69. Mock - esempio <?php class SubjectTest extends PHPUnit_Framework_TestCase { public function testObserversAreUpdated() { // Create a mock for the Observer class, // only mock the update() method. $observer = $this->getMock('Observer', array('update')); // Set up the expectation for the update() method // to be called only once and with the string 'something' // as its parameter. $observer->expects($this->once()) ->method('update') ->with($this->equalTo('something')); // Create a Subject object and attach the mocked // Observer object to it. $subject = new Subject; $subject->attach($observer); // Call the doSomething() method on the $subject object // which we expect to call the mocked Observer object's // update() method with the string 'something'. $subject->doSomething(); } } ?>
Una pratica che permette di verificare che singole unità di codice facciano effettivamente ciò per cui sono state scritte. Un'unità è la più piccola parte delle'applicazione. Nel caso ideale ogni test è indipendente dagli altri: per ottenere quest'isolamento possiamo ricorrere all'utilizzo di stubs, mocks, fakes...
Le chiavi della definizione sono le seguenti: parliamo di singole unità di codice
...dove l'unità di codice è la più piccola parte testabile dell'applicazione: - PROCEDURALE: intero programma, funzioni - OO: metodi
Il vincolo è quello di poter testare la singola unità di codice in ISOLAMENTO dal resto dell'applicazione.
Legittima se non si conoscono i test... La regola dell'80/20...
Perchè? Perchè non hai test. Rompi il codice e tu non lo sai. Un altro dev rompe il tuo codice e tu non lo sai. Tu rompi il codice dell'altro dev e lui non lo sa.
Ecco quindi che il “non ho tempo” significa “non ho tempo di imparare a testare il codice e voglio solo scrivere codice reale ORA”. Pigrizia Poca lungimiranza
La locuzione latina Beati monoculi in terra caecorum (pronuncia: beàti monòculi in tèrra cecòrum)
Lanciare la suite di test frequentemente permette di individuare i bug. E' inevitabile. Individuare i bug subito permette di risolverli più facilmente dato che il codice è ancora “fresco” in testa. Inoltre si possono aggiungere nuovi test per bug extra prima di fixarli per essere sicuri di cosa si sta modificando.
Individuare e risolvere i bug poco tempo dopo la loro introduzione è molto più veloce che trovare, analizzare e risolvere un bug tra 1 o 6 mesi. Inoltre si evita di rompere altre parti dell'applicazione con l'inserimento di nuove feature.
Automatizzare l'esecuzione della suite di test è il valore in più. Possono essere lanciati velocemente da console o da un refresh del browser. Verificano tutto. Il costo di scrittura è una-tantum, vengono eseguiti migliaia di volte. GRATIS.
Modificare un metodo mantenendo inalterati i dati che restituisce. Inserire nuove funzionalità senza rompere le altre. Senza test non è possibile fare REFACTORING.
Scrivere i test spinge a pensare maggiormente come mantenere le cose semplici: disaccoppiate e flessibili. Si traduce in facilità di test. Se è difficile da testare non è ben progettato. Se è troppo corposo potrebbe essere necessario separare le cose in classi diverse...
Il test descrive un caso d'uso o un esempio. Un esempio spesso vale più di mille parole. &quot;testdox&quot; strumento che elenca (sfruttando i nomi dei metodi) ciò che l'esempio asserisce. Essenzialmente rappresenta una specifica delle classi più leggibile per i non sviluppatori (DBA).
Un errore comune è quello di buttarsi a capofitto nello scrivere codice senza una strategia ben definita. Come essere in una stanza buia, ci si muove a tentativi tornando indietro per poi ripartire perdendo un sacco di tempo per trovare l'uscita. Dovendo scrivere i test si è obbligati a pensare al problema in modo diverso per trovare soluzioni semplici, eleganti e pratiche. E' più facile andare avanti, tornare indietro è raro.
Poter verificare il codice, individuare bug più facilmente, apportare modifiche senza correre rischi permette di spendere più tempo sviluppando nuove feature invece che risolvendo problemi. Si guarda sempre avanti.
Se si sono scritti test per coprire tutte le feature richieste e tutti passano è ragionevole pensare che il codice sia finito. Questo si mischia bene con le pratiche XP/Agile dove i test servono anche per verificare i requisiti funzionali.
Avere fiducia nel proprio codice, poter cambiare facilmente le cose, risolvere i problemi con criterio ed in modo elegante, poter fare refactoring sono tutte cose che fanno apprezzare il processo.
Nella documentazione trovate tutte le assertion disponibili, vi assicuro che ce ne sono davvero molte...
setUp() and tearDown() are nicely symmetrical in theory but not in practice. In practice, you only need to implement tearDown() if you have allocated external resources like files or sockets in setUp(). If your setUp() just creates plain PHP objects, you can generally ignore tearDown(). However, if you create many objects in your setUp(), you might want to unset() the variables pointing to those objects in your tearDown() so they can be garbage collected. The garbage collection of test case objects is not predictable.
Nella definizione di unit testing abbiamo visto che eseguire i testi in isolamento è importante. A volte non possiamo utilizzare i componenti reali da cui dipende ciò che stiamo testando ecco quindi che entrano in campo i Double. Un Double rimpiazza un DOC. Un Double non dev'essere per forza uguale al DOC che rimpiazza, deve avere la stessa API per far credere al sistema che si tratta del componente vero!