Test Driven Development, sau “dezvoltare prin teste” este o tehnica pentru a scrie programe.
Detalii pe wikipedia.
Este o disciplina în același sens în care un chirurg are disciplina de a se spăla pe mâini înainte de a opera 🙂
Are 3 reguli:
- Nu scrie cod de producție (cod final) doar dacă este pentru a face ca un test care nu mergea, sa meargă. (Write NO production code except to pass a failing test)
- Scrie cod de test doar cât este nevoie pentru a avea un test care nu merge (e ok dacă nu se compilează). (Write only enough of a test to demonstrate a failure)
- Scrie cod de producție doar e destul pentru a face un test sa meargă. (Write only enough production code to pass the test)
Majoritatea mediilor de programare “moderne” incorporează posibilitatea de a scrie și de a executa teste.
In Java, se poate folosi JUnit.
Cele 3 reguli de mai sus, se pot formula și astfel:
- Rezultatul execuției testelor sa fie ROSU. (status red)
- Rezultatul execuției testelor sa fie VERDE. (status green)
- Modificare cod pentru a deveni cod “mai curat“. (re-factor)
Un test este o metoda, o funcție.
Orice test ar trebui sa aibă 4 parți:
- Aranjare – pregătim terenul pentru test
- Apel – apelam funcția pe care dorim sa o testam
- Aserțiune – comparam valoarea returnata de funcția pe care dorim sa o testam cu valoarea așteptata
- Anihilare – curățam orice inițializări (făcute la pasul 1) care pot afecta în continuare sistemul.
Exemplu:
Sa scriem un program pentru stiva. Stiva este o lista în care putem adăuga elemente “deasupra” altor elemente, și putem “scoate” doar elementul cel mai de sus.
Imaginați-va mai multe farfurii puse unele peste altele. Când adaugăm o farfurie noua, o vom așeza deasupra celorlalte. Când vrem sa luam o farfurie, o vom lua pe cea mai de sus.
Începem cu un fișier nou Java, fișierul în care vom scrie testele: StackTest.java
package stiva;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class TestStiva {
@Test
public void testStiva() {
Stiva stiva = new Stiva();
}
}
Daca incercam sa executam acest test, obtinem eroare: cannot find symbol: class Stiva.
Suntem in faza 1) Status Red si in acelasi timp suntem in faza 1) Aranjare.
Vom creea o clasa noua: Stiva
package stiva;
public class Stiva {
}
Acum putem executa testul, iar acesta se executa cu succes. Suntem in faza 2) Status Green.
Observam ca nu sunt lucruri de modificat pe moment, deci sărim peste faza 3)
De asemenea, observam ca încă nu am testat nimic 🙂
Vom testa ca o stiva goala are zero elemente, pasul 2 – Apel si 3 – Asertiune
Adaugam o linie noua in fisierul cu teste StackTest.java:
assertEquals(0, stiva.getSize());
Am apelat o metoda inexistenta, numita getSize() din clasa Stiva.
Vom creea aceea metoda. Acum Stiva.java arata astfel:
package stiva;
public class Stiva {
private int size = -1;
public int getSize() {
return size;
}
}
Pasul 2 – Apel și 3 – Asertiune este complet.
Executam, și vedem ca testul nu merge: Expected: 0 — Actual: -1
Suntem în faza 1) Status Red
Modificam linia
private int size = -1;
în
private int size = 0;
și executam testul din nou. Merge! Suntem în faza 2) Status Green.
Observam ca nu sunt lucruri de modificat pe moment, deci sărim peste faza 3)
Avem cod de producție(Stiva.java), avem o funcționalitate pentru Stiva: dimensiunea stivei (getSize()).
Fiecare linie din codul de producție este acoperita de cel puțin un test 🙂
Sa scriem si 2 functii mai utile: Push si inversa sa: Pop
Pentru asta, vom scrie testele care testeaza Push si Pop
@Test
public void testPush() {
Stiva stiva = new Stiva(); //aranjare
stiva.push(10); //apel
assertEquals(1, stiva.getSize()); //asertiune
//anihilare - nu este nevoie
}
Încercam sa executam și vedem ca metoda push nu exista. (status red)
Pentru a trece din status red in status green vom scrie cat mai putin cod cu putinta, dar destul pentru a face ca testele de mearga, sa devina verzi.
Pentru mine, codul de mai jos, scris in fisierul:Stiva.java pare a fi cel mai scurt:
public void push(int nr) {
size++;
}
Continuam cu partea 3) Modificare cod pentru a deveni cod “mai curat“. (re-factor)
Observam ca partea de aranjare:
Stiva stiva = new Stiva();
se repeta de 2 ori in cele 2 teste. Putem sa extragem aceasta initializare si sa o scriem 1 data intr-o metoda de “setup”, care se executa inainte de fiecare test. Codul devine: StackTest.java
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class TestStiva {
private Stiva stiva;
@Before
public void setUp() throws Exception {
stiva = new Stiva();
}
@Test
public void testStiva() {
assertEquals(0, stiva.getSize());
}
@Test
public void testPush() {
stiva.push(10); //apel
assertEquals(1, stiva.getSize()); //asertiune
//anihilare - nu este nevoie
}
}
Va urma