Test Driven Development cu JUnit 5. Partea a doua.
Test Driven Development cu JUnit 5. Partea a doua.
Cea de-a doua parte a seriei noastre despre test driven development cu JUnit 5.
13 Jan 2021
700
Other articles
Object-relational Mapping folosind JPA, Hibernate si Spring Data JPA. Persistence cu JPA
Cum sa interogam Kafka Streaming Data?
Procrastinarea. Care sunt avantajele ei?
Object-relational Mapping folosind JPA, Hibernate si Spring Data JPA
Procrastinarea
Cerinte. De ce avem nevoie de ele?
Dezvolta-ti abilitatile cu training-urile noastre
Programarea reactiva Java. Implementari
Testarea software. Intrebari tipice si raspunsuri. Continuare
Testarea software. Intrebari tipice si raspunsuri
2. Aplicatia de flight-management
Ca exemplu pentru a arata TDD cu JUnit 5 in actiune vom dezvolta o aplicatie de flight-management. In acest moment aplicatia poate sa creeze si sa stabileasca zboruri dar si sa adauge pasageri sau sa ii scoata de pe lista de zboruri.
Vom trece prin scenarii prin care ar trece in mod normal un programator. Vom incepe cu aplicatia non-TDD care trebuie sa faca mai multe lucruri printre care sa urmareasca politicile companiei pentru pasagerii regular si VIP. Trebuie sa intelegem aplicatia si sa ne asiguram ca implementeaza lucrurile la care ne asteptam sa fie implementate. Asa ca trebuie sa acoperim codul existent cu unit tests. O data ce am facut asta, vom aborda o alta provocare: adaugarea de noi functionalitati intelegand in primul rand ce trebuie facut, apoi scrierea de teste care esueaza si apoi scrierea de cod care rezolva testele. Acest ciclu de lucru este unul din elementele de baza in TDD.
Aplicatia de flight-management este scrisa in Java cu ajutorul Maven. Software-ul trebuie sa respecte politica legata de adaugarea de pasageri si inlaturarea acestora din zboruri. Zborurile pot sa fie diferite: in acest moment, avem doar zboruri la clasa economy si business, dar alte tipuri de zboruri pot sa fie adaugate mai tarziu, in functie de cerintele clientului. Atat pasagerii VIP cat si cei regular pot sa fie adaugati la clasa economy, dar doar cei VIP pot sa fie adaugati la clasa business.
Exista si o politica legata de inlaturarea pasagerilor: un pasager regular poate sa fie scos dintr-un zbor, dar unul VIP nu. Dupa cum putem vedea in cele doua diagrame, business logic initial se concentreaza pe luarea deciziilor.
Hai sa ne uitam la designul initial al acestei aplicatii. Are un camp care se numeste flightType in Flight class. Valoarea sa determina comportamentul metodelor addPassenger si removePassenger. Programatorii trebuie sa se concentreze pe luarea deciziilor la nivelul codului pentru aceste doua metode.
public class Passenger {
private String name; #1
private boolean vip; #2
public Passenger(String name, boolean vip) { #3
this.name = name; #3
this.vip = vip; #3
} #3
public String getName() { #4
return name; #4
} #4
public boolean isVip() { #5
return vip; #5
} #5
}
In cod facem urmatoarele lucruri:
- Clasa Passenger contine un camp pentru nume #1 si un getter pentru el #4
- Contine si un camp VIP #2 impreuna cu un getter #5
- Constructorul clasei Passenger initializeaza campurile pentru nume si VIP #3
public class Flight {
private String id; #1
private List passengers = new ArrayList(); #2
private String flightType; #3
public Flight(String id, String flightType) { #4
this.id = id; #4
this.flightType = flightType; #4
} #4
public String getId() { #5
return id; #5
} #5
public List getPassengersList() { #6
return Collections.unmodifiableList(passengers); #6
} #6
public String getFlightType() { #7
return flightType; #7
} #7
public boolean addPassenger(Passenger passenger) {
switch (flightType) { #8
case "Economy": #9
return passengers.add(passenger); #9
case "Business": #10
if (passenger.isVip()) { #10
return passengers.add(passenger); #10
} #10
return false; #10
default: #11
throw new RuntimeException("Unknown type: " + flightType); #11
}
}
public boolean removePassenger(Passenger passenger) {
switch (flightType) { #12
case "Economy": #13
if (!passenger.isVip()) { #13
return passengers.remove(passenger); #13
} #13
return false; #13
case "Business": #14
return false; #14
default: #15
throw new RuntimeException("Unknown type: " + flightType); #15
}
}
}
Codul de mai jos arata clasa Flight.
In codul de mai sus facem urmatoarele lucruri:
- Clasa Flight contine un identifier #1 impreuna cu un getter #5, o lista de pasageri initializata sub forma unei liste goale #2 impreuna cu un getter #6, si un flight type #3 cu un getter #7.
- Constructorul clasei Flight initializeaza campurile pentru id si flightType #4.
- Metoda addPassenger verifica tipul de zbor #8. Daca este un zbor la clasa economy, putem sa adaugam orice tip de pasageri #9. Daca este un zbor la clasa business, doar pasagerii VIP pot sa fie adaugati #10. Altfel (daca zborul nu este nici la clasa economy si nici la business), metoda va genera o exceptie, deoarece nu poate sa abordeze un tip de zbor necunoscut #11.
- Metoda removePassenger verifica tipul de zbor #12. Daca este un zbor la clasa economy, doar pasagerii regular pot sa fie inlaturati #13. Daca este un zbor la clasa business, pasagerii nu pot sa fie inlaturati #14. Altfel (daca zborul nu este nici la clasa economy si nici la business), metoda va genera o exceptie, deoarece nu poate sa abordeze un tip de zbor necunoscut #15.
Aplicatia nu are inca teste. Insa, programatorii initiali au scris niste cod in cadrul caruia au urmat pur si simplu executia si au comparat-o cu asteptarile. Spre exemplu, exista o clasa Airport, care contine o metoda principala care actioneaza ca un client pentru clasele Flight si Passenger si lucreaza cu diferite tipuri de zboruri si pasageri.
public class Airport {
public static void main(String[] args) {
Flight economyFlight = new Flight("1", "Economy"); #1
Flight businessFlight = new Flight("2", "Business"); #1
Passenger james = new Passenger("James", true); #2
Passenger mike = new Passenger("Mike", false); #2
businessFlight.addPassenger(james); #3
businessFlight.removePassenger(james); #3
businessFlight.addPassenger(mike); #4
economyFlight.addPassenger(mike); #5
System.out.println("Business flight passengers list:"); #6
for (Passenger passenger: businessFlight.getPassengersList()) { #6
System.out.println(passenger.getName()); #6
} #6
System.out.println("Economy flight passengers list:"); #7
for (Passenger passenger: economyFlight.getPassengersList()) { #7
System.out.println(passenger.getName()); #7
} #7
}
}
In codul de mai sus:
- Initializam un zbor la clasa economy si un zbor la business #1. Il initializam si pe James ca pasager VIP si Mike ca pasager regular #2.
- Incercam sa il adaugam pe James si sa il indepartam din zborul la clasa business #3, si apoi incercam sa il adaugam pe Mike si sa il indepartam de la zborul de business #4 si cel economy #5.
- Printam lista de pasageri din zborul de business #6 si cel economy #7.
Rezultatul functionarii acestui program apare in figura de mai jos 20.4. James, un pasager VIP, a fost adaugat la zborul de business si nu il putem indeparta. Mike, un pasager regular, nu a putut sa fie adaugat la zborul de business, dar l-am putut adauga la zborul economy.
Pana acum, lucrurile par sa functioneze dupa cum ne-am asteptat, conform politicilor pe care le-am definit anterior. Pentru a construi o aplicatie de incredere si pentru a putea sa intelegem si sa implementam usor si in siguranta business logic, schimbam aplicatia conform TDD.
Vrei sa inveti mai multe despre aceasta tehnologie? Descopera cursurile noastre.
Catalin Tudose
Java and Web Technologies Expert