Test Driven Development cu JUnit 5. Partea a cincea
Cel de-al cincilea articol din seria noastra despre test driven development cu JUnit 5. De data aceasta ne uitam la cum putem introduce functionalitati noi folosind TDD.
5. Introducerea de noi functionalitati folosind TDD
Primele functionalitati noi pe care le vom implementa sunt un nou tip de zbor — premium — si politicile legate de acest tip de zbor. Exista o politica pentru a adauga un pasager: daca pasagerul este VIP, pasagerul ar trebui adaugat la zborul premium; altfel, cererea trebuie respinsa. Exista si o politica legata de inlocuirea unui pasager: daca este necesar, un pasager poate sa fie inlocuit de pe lista pentru zbor.
Vrem sa profitam de faptul ca lucram cu TDD si sa facem mai mult refactoring — de data aceasta, la nivel de teste. Facem asta in spiritulRule of Three, conform lui Don Roberts.
Prima oara cand faci ceva, fa acel lucru. A doua oara cand faci ceva similar, ridici din sprancene la duplicare, dar mergi in continuare. A treia oara cand faci ceva similar, faci refactoring.
Asa ca la trei abateri faci refactoring.
Dupa ce primim cerintele pentru implementarea acestui al treilea tip de zbor, este timpul sa grupam testele existente folosind JUnit 5 @Nested annotation si apoi sa implementam zborul premium in mod similar. Urmeaza apoi clasa refactored AirportTest si dupa trecem la codul pentru zborul premium.
public class AirportTest {
@DisplayName(“Given there is an economy flight”)
class EconomyFlightTest {
private Flight economyFlight; #1
private Passenger mike; #1
private Passenger james; #1
economyFlight = new EconomyFlight(“1”); #2
mike = new Passenger(“Mike”, false); #2
james = new Passenger(“James”, true); #2
@Nested #3
@DisplayName(“When we have a regular passenger”) #3
class RegularPassenger { #3
“Then you can add and remove him from an economy flight”) #4
public void testEconomyFlightRegularPassenger() {
assertAll( #5
“Verify all conditions for a regular passenger #5
and an economy flight”, #5
() -> assertEquals(“1”, economyFlight.getId()), #5
() -> assertEquals(true, #5
economyFlight.addPassenger(mike)), #5
() -> assertEquals(1, #5
economyFlight.getPassengersList().size()), #5
() -> assertEquals(“Mike”, #5
economyFlight.getPassengersList() #5
.get(0).getName()), #5
() -> assertEquals(true, #5
economyFlight.removePassenger(mike)), #5
() -> assertEquals(0, #5
economyFlight.getPassengersList().size()) #5
@Nested #3
@DisplayName(“When we have a VIP passenger”) #3
class VipPassenger { #3
@DisplayName(“Then you can add him but #4
cannot remove him from an economy flight”) #4
public void testEconomyFlightVipPassenger() {
assertAll(“Verify all conditions for a VIP passenger #5
and an economy flight”, #5
() -> assertEquals(“1”, economyFlight.getId()), #5
() -> assertEquals(true, #5
economyFlight.addPassenger(james)), #5
() -> assertEquals(1, #5
economyFlight.getPassengersList().size()), #5
() -> assertEquals(“James”, #5
economyFlight.getPassengersList().get(0).getName()), #5
() -> assertEquals(false, #5
economyFlight.removePassenger(james)), #5
() -> assertEquals(1, #5
economyFlight.getPassengersList().size()) #5
@DisplayName(“Given there is a business flight”)
class BusinessFlightTest {
private Flight businessFlight; #1
private Passenger mike; #1
private Passenger james; #1
businessFlight = new BusinessFlight(“2”); #2
mike = new Passenger(“Mike”, false); #2
james = new Passenger(“James”, true); #2
@Nested #3
@DisplayName(“When we have a regular passenger”) #3
class RegularPassenger { #3
@DisplayName(“Then you cannot add or remove him #4
from a business flight”) #4
public void testBusinessFlightRegularPassenger() {
assertAll(“Verify all conditions for a regular passenger #5
and a business flight”, #5
() -> assertEquals(false, #5
businessFlight.addPassenger(mike)), #5
() -> assertEquals(0, #5
businessFlight.getPassengersList().size()), #5
() -> assertEquals(false, #5
businessFlight.removePassenger(mike)), #5
() -> assertEquals(0, #5
businessFlight.getPassengersList().size()) #5
@Nested #3
@DisplayName(“When we have a VIP passenger”) #3
class VipPassenger { #3
@DisplayName(“Then you can add him but cannot remove him #4
from a business flight”) #4
public void testBusinessFlightVipPassenger() {
assertAll(“Verify all conditions for a VIP passenger #5
and a business flight”, #5
() -> assertEquals(true, #5
businessFlight.addPassenger(james)), #5
() -> assertEquals(1, #5
businessFlight.getPassengersList().size()), #5
() -> assertEquals(false, #5
businessFlight.removePassenger(james)), #5
() -> assertEquals(1, #5
businessFlight.getPassengersList().size()) #5
In codul de mai sus:
- In nested classes EconomyFlightTest si BusinessFlightTest existente, grupam campurile legate de zbor si pasager, pentru ca vrem sa mai adaugam un nivel de testare si sa refolosim aceste campuri pentru toate testele legate de un anumit tip de zbor #1. Initializam aceste campuri inainte de executarea fiecarui test #2.
- Introducem un nou nesting level pentru a testa diferitele tipuri de pasageri. Folosim JUnit 5 @DisplayName annotation pentru a eticheta clasele intr-un mod mai expresiv si mai usor de urmarit #3. Toate aceste etichete incep cu keywordul When.
- Etichetam toate testele existente cu ajutorul JUnit 5 @DisplayName annotation #4. Toate aceste etichete incep cu keywordul Then.
- Facem refactoring pe verificarea conditiilor folosind metoda assertAll JUnit 5 si grupand toate conditiile existente anterior, care acum pot sa fie citite fluent #5.
Asa am facut refactoring pe testele existente, pentru a facilita continurea muncii in stilul TDD si pentru a introduce business logic pentru zborurile premium. Daca rulam testele acum, putem urmari cu usurinta modul in care lucreaza si verifica business logic. Orice programator nou care s-ar alatura acestui proiect va putea sa foloseasca aceste teste pe post de documentatie!
Vrei sa inveti mai multe despre aceasta tehnologie? Descopera cursurile noastre.
Catalin Tudose
Java and Web Technologies Expert
Originally published at https://www.luxoft-training.ro.