Test Driven Development z użyciem JUnit 5. Część 5

Test Driven Development z użyciem JUnit 5. Część 5

Piąty artykuł z naszej serii o programowaniu sterowanym testami w JUnit 5. Tym razem przyjrzymy się, jak wprowadzić nowe funkcje za pomocą TDD.
27 wrz 2021 843

5. Wprowadzenie nowych funkcji za pomocą TDD


Pierwsze nowe funkcje, które wprowadzimy, to nowy typ lotu - premium - i zasady dotyczące tego typu lotu. Istnieje zasada dodawania pasażera: jeśli pasażer jest VIP-em, należy go dodać do lotu premium; w przeciwnym razie wniosek należy odrzucić. Istnieją również zasady dotyczące usuwania pasażera: w razie potrzeby pasażer może zostać usunięty z lotu.

Introducing new features using TDD 1.png

Introducing new features using TDD 2.png






Chcielibyśmy w większym stopniu wykorzystać działający styl TDD i przeprowadzić więcej refaktoryzacji - tym razem do testów. Jest to zgodne z duchem "reguły trzech", jak stwierdził Don Roberts.

Kiedy robisz coś po raz pierwszy, po prostu to robisz. Za drugim razem, gdy robisz coś podobnego, "skrzywisz się" z powodu duplikacji, ale i tak robisz to samo. Za trzecim razem, gdy robisz coś podobnego, refaktoryzujesz.

A więc trzy "strike'i" i refaktoryzujesz.

Po otrzymaniu wymagania dotyczącego realizacji tego trzeciego typu lotu, pora na pogrupowanie istniejących testów za pomocą adnotacji JUnit 5 @Nested, a następnie zaimplementowanie wymogu lotu premium w podobny sposób. Poniżej znajduje się refaktoryzowana klasa AirportTest przed przejściem do pracy na lot premium.

public class AirportTest {


    @DisplayName("Given there is an economy flight")

    @Nested

    class EconomyFlightTest {

        private Flight economyFlight;                                    #1

        private Passenger mike;                                          #1

        private Passenger james;                                         #1

        @BeforeEach

        void setUp() {

            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

            @Test

            @DisplayName(

               "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

                );                                                       #5

            }

        }

        @Nested                                                          #3

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

        class VipPassenger {                                             #3

            @Test

            @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")

    @Nested

    class BusinessFlightTest {

        private Flight businessFlight;                                   #1

        private Passenger mike;                                          #1

        private Passenger james;                                         #1

        @BeforeEach

        void setUp() {

            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

            @Test

            @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

            @Test

            @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

                );

            }

        }

    }

}


W tym listingu:

  • W istniejących zagnieżdżonych klasach EconomyFlightTest i BusinessFlightTest grupujemy pola lotu i pasażerów, ponieważ chcielibyśmy dodać jeszcze jeden poziom testowania i ponownie wykorzystać te pola do wszystkich testów dotyczących określonego typu lotu # 1. Inicjalizujemy te pola przed wykonaniem każdego testu # 2.
  • Wprowadzamy nowy poziom zagnieżdżenia, aby przetestować różne typy pasażerów. Używamy adnotacji JUnit 5 @DisplayName do oznaczania klas w sposób bardziej wyrazisty i łatwiejszy do naśladowania # 3. Wszystkie te etykiety zaczynają się od słowa kluczowego When.
  • Oznaczamy wszystkie istniejące testy za pomocą adnotacji JUnit 5 @DisplayName # 4. Wszystkie te etykiety zaczynają się od słowa kluczowego Then.
  • Dokonujemy refaktoryzacji sprawdzania warunków za pomocą metody assertAll JUnit 5 i grupując wszystkie wcześniej istniejące warunki, które można teraz płynnie odczytać # 5.

W ten sposób przeredagowaliśmy istniejące testy, aby ułatwić dalszą pracę w stylu TDD i wprowadzić nową, wymaganą logikę biznesową lotów premium. Jeśli uruchomimy testy teraz, możemy łatwo prześledzić sposób ich działania i sprawdzanie logiki biznesowej. Każdy nowy programista dołączający do projektu uzna te testy za niezwykle cenne jako część dokumentacji!

Interesujesz się JUnit? Sprawdź nasze szkolenia


Catalin Tudose
Java and Web Technologies Expert


Udostępnij

Masz jeszcze jakieś pytania?
Skontaktuj się z nami
Thank you!
The form has been submitted successfully.