Test Driven Development cu JUnit 5. Partea a sasea

Ultimul articol din seria noastra despre Test Driven Development cu JUnit 5.

Feb 17, 2021 182
In acest ultim articol mergem mai departe cu implementarea clasei PremiumFlight. Vom crea PremiumFlight ca o subclasa a Flight si trecem peste metodele addPassenger si removePassenger, dar acestea vor actiona ca stubs—nu fac nimic, ci pur si simplu returneaza fals. Comportamentul lor va fi extins mai tarziu. Stilul TDD se bazeaza mai intai pe crearea de teste si apoi business logic.

public class PremiumFlight extends Flight {                              #1

   public PremiumFlight(String id) {                                     #2

      super(id);                                                         #2

   }                                                                     #2

   @Override

   public boolean addPassenger(Passenger passenger) {                    #3

      return false;                                                      #3

   }                                                                     #3

   @Override

   public boolean removePassenger(Passenger passenger) {                 #4

       return false;                                                     #4

   }                                                                     #4

}


In codul de mai sus:

  • Declaram clasa PremiumFlight care extinde Flight #1, si creem un constructor pentru ea #2.
  • Creem metodele addPassenger #3 si removePassenger #4 ca stubs, fara nici o business logic. Pur si simplu returneaza fals.

Acum implementam testele conform premium flight business logic de la figurile 20.8 si 20.9.

public class AirportTest {

    [...]

    @DisplayName("Given there is a premium flight")                      #1

    @Nested                                                              #1

    class PremiumFlightTest {                                            #1

        private Flight premiumFlight;                                    #2

        private Passenger mike;                                          #2

        private Passenger james;                                         #2

        @BeforeEach

        void setUp() {

            premiumFlight = new PremiumFlight("3");                      #3

            mike = new Passenger("Mike", false);                         #3

            james = new Passenger("James", true);                        #3

        }

        @Nested                                                          #4

        @DisplayName("When we have a regular passenger")                 #4

        class RegularPassenger {                                         #4

           

            @Test                                                        #5

            @DisplayName("Then you cannot add or remove him              #5

                          from a premium flight")                        #5

            public void testPremiumFlightRegularPassenger() {            #5

                assertAll("Verify all conditions for a regular passenger #6

                           and a premium flight",                        #6

                        () -> assertEquals(false,                        #7

                              premiumFlight.addPassenger(mike)),         #7

                        () -> assertEquals(0,                            #7

                              premiumFlight.getPassengersList().size()), #7

                        () -> assertEquals(false,                        #8

                              premiumFlight.removePassenger(mike)),      #8

                        () -> assertEquals(0,                            #8

                              premiumFlight.getPassengersList().size())  #8

                );

            }

        }

        @Nested                                                          #9

        @DisplayName("When we have a VIP passenger")                     #9

        class VipPassenger {                                             #9

            @Test                                                        #10

            @DisplayName("Then you can add and remove him              #10

                          from a premium flight")                      #10

            public void testPremiumFlightVipPassenger() {              #10

                assertAll("Verify all conditions for a VIP passenger   #11

                           and a premium flight",                      #11

                        () -> assertEquals(true,                       #12

                              premiumFlight.addPassenger(james)),      #12

                        () -> assertEquals(1,                          #12

                              premiumFlight.getPassengersList().size()), #12

                        () -> assertEquals(true,                       #13

                              premiumFlight.removePassenger(james)),   #13

                        () -> assertEquals(0,                          #13

                              premiumFlight.getPassengersList().size())  #13

                );

            }

        }

    }

}


In codul de mai sus:

  • Declaram nested class PremiumFlightTest #1 care contine campurile ce reprezinta zborul si pasagerii #2 care sunt construiti inainte de fiecare test #3.
  • Cream doua clase nested la nivelul doi in PremiumFlightTest: RegularPassenger #4 si VipPassenger #9. Folosim adnotarea JUnit 5 @DisplayName pentru a eticheta aceste clase cu keyword-ul When.
  • Inseram un test in fiecare dintre clasele RegularPassenger #5 si VipPassenger #10 nou adaugate. Etichetam aceste teste cu adnotarea JUnit 5 @DisplayName incepand cu keyword-ul Then.
  • Testam un premium flight si un regular passenger, folosind metoda assertAll pentru a verifica conditii multiple #6. Verificam ca nu poate sa fie adaugat un pasager la un premium flight si ca daca incercam sa adaugam un pasager acest lucru nu schimba dimensiunea listei de pasageri #7. Apoi, verificam faptul ca nu putem sa eliminam un pasager dintr-un premium flight si ca daca incercam asta nu schimbam dimensiunea listei de pasageri #8.
  • Testarea unui premium flight si VIP passenger, unde folosim din nou assertAll #11. Verificam daca putem adauga un pasager la un premium flight si ca facand asta lista de pasageri creste #12. Apoi, verificam faptul ca putem elimina un pasager dintr-un premium flight si ca daca facem asta lista de pasageri devine mai mica #13.

Test Driven Development with JUnit 5. Part 6.jpg



Unul din teste esueaza in acest moment, dar nu este o problema. Din contra: este exact lucrul la care ne-am asteptat. Tine-ti minte ca daca lucram cu TDD inseamna ca suntem condusi de teste, asa ca mai intai creem testul ca sa esueze si apoi scriem cod care sa faca testul sa treaca. Dar mai este ceva remarcabil aici: testul pentru un premium flight si regular passenger a trecut deja cu succes. Acest lucru inseamna ca business logic existent (metodele addPassenger si removePassenger care returneaza fals) este indeajuns pentru acest caz. Intelegem faptul ca trebuie sa ne concentram asupra VIP passenger. Ca sa il citam pe Kent Beck din nou, „TDD te ajuta sa ramai atent la provocarile cheie, atunci cand trebuie, ca sa ai un design mai clar si ca sa poti sa rafinezi design-ul tau pe masura ce afli lucruri noi. TDD iti permite sa capeti incredere in cod de-alungul timpului.”

Asa ca revenim la clasa PremiumFlight si adaugam business logic doar pentru VIP passengers. Lasandu-ne condusi de teste, trecem direct la subiect.

public class PremiumFlight extends Flight {

   public PremiumFlight(String id) {

      super(id);

   }

   @Override

   public boolean addPassenger(Passenger passenger) {

      if (passenger.isVip()) {                                           #1

         return passengers.add(passenger);                               #1

      }                                                                  #1

      return false;

   }

   @Override

   public boolean removePassenger(Passenger passenger) {

        if (passenger.isVip()) {                                         #2

            return passengers.remove(passenger);                         #2

        }                                                                #2

       return false;

   }

}


In codul de mai sus:

  • Adaugam pasagerul doar daca este VIP #1.
  • Eliminam pasagerul doar daca pasagerul este VIP #2.

Testele ruleaza cum trebuie si avem 100% code coverage.


Concluzii


In cadrul acestui articol:

  • Am examinat conceptul TDD si am aratat cum ne ajuta sa dezvoltam aplicatii sigure deoarece testele previn introducerea de bug-uri in cod si functioneaza si ca documentatie.
  • Am pregatit o aplicatie software non-TDD pentru a trece la TDD adaugand teste hierarchical JUnit 5 care acopera business logic existent.
  • Am facut refactoring si am imbunatatit calitatea codului acestei aplicatii TDD inlocuind conditional cu polymorphism in timp ce ne bazam pe testele pe care le dezvoltam.
  • Am implementat functionalitati noi lucrand cu TDD, incepand cu scrierea de teste si apoi implementand business logic.


Vrei sa inveti mai multe despre aceasta tehnologie? Descopera cursurile noastre.

Catalin Tudose
Java and Web Technologies Expert

Daca iti place acest articol, distribuie-l si prietenilor tai!




Mai ai intrebari?
Contacteaza-ne.
Thank you.
Your request has been received.