~~NOCACHE~~ ~~REVEAL theme=simple&disableLayout=0&transition=none&controls=1&show_progress_bar=1&build_all_lists=0&show_image_borders=0&horizontal_slide_level=2&enlarge_vertical_slide_headers=0&show_slide_details=1&open_in_new_window=1&size=1024x768~~ ===== Testowanie aplikacji Spring Boot ===== ===== Testy jednostkowe ===== * [[https://junit.org/|JUnit 5]] - framework do pisania i uruchamiania testów jednostkowych w Javie * [[https://site.mockito.org/|Mockito]] - framework do mockowania zależności w testach jednostkowych. * [[https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing|Spring Boot Test]] - wsparcie dla testów jednostkowych i integracyjnych. * ''spring-boot-starter-test'' - starter zawierający wszystkie potrzebne zależności (JUnit, Mockito, AssertJ). * ''@SpringBootTest'' - uruchamia kontekst Spring podczas testów. * ''@MockBean'' - tworzy mocki dla zależności. * ''@WebMvcTest'' - testowanie warstwy webowej (kontrolerów). * ''@DataJpaTest'' - testowanie warstwy dostępu do danych (repozytoriów). ===== Struktura testów ===== * Testy jednostkowe - testowanie pojedynczych klas i metod, izolacja od reszty aplikacji. * Testy integracyjne - testowanie współpracy między komponentami, uruchomienie kontekstu Spring. * Testy end-to-end - testowanie całej aplikacji, symulacja rzeczywistego użytkowania. ===== Struktura projektu z testami ===== src/ ├── main/ │ └── java/com/example/app/ │ ├── controller/ │ │ └── UserController.java │ ├── service/ │ │ └── UserService.java │ ├── repository/ │ │ └── UserRepository.java │ └── model/ │ └── User.java └── test/ └── java/com/example/app/ ├── controller/ │ └── UserControllerTest.java ├── service/ │ └── UserServiceTest.java ├── repository/ │ └── UserRepositoryTest.java └── integration/ └── UserFlowIntegrationTest.java ===== JUnit ===== * JUnit to framework do pisania testów jednostkowych w Javie. * Przypadek testowy - metoda testowa, która sprawdza poprawność działania konkretnej funkcjonalności.\\ Adnotacja ''@Test'' oznacza metodę jako testową. * Adnotacje - zarządzanie cyklem życia testów: * ''@Test'' - oznacza metodę jako testową. * ''@BeforeEach'' - metoda wykonywana przed każdym testem. * ''@AfterEach'' - metoda wykonywana po każdym teście. * ''@BeforeAll'' - metoda wykonywana raz przed wszystkimi testami. * ''@AfterAll'' - metoda wykonywana raz po wszystkich testach. ===== Assercje ===== * Assercje - metody sprawdzające, czy wynik testu jest zgodny z oczekiwaniami. * ''assertEquals(expected, actual)'' - sprawdza równość wartości. * ''assertTrue(condition)'' - sprawdza, czy warunek jest prawdziwy. * ''assertFalse(condition)'' - sprawdza, czy warunek jest fałszywy. * ''assertNotNull(object)'' - sprawdza, czy obiekt nie jest null. * ''assertThrows(exceptionClass, executable)'' - sprawdza, czy wykonanie kodu rzuca określony wyjątek. ===== Przykład testu jednostkowego ===== Przykład prostego testu jednostkowego z użyciem JUnit: import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Assertions; public class CalculatorTest { @Test public void testAddition() { // Arrange - przygotowanie danych testowych Calculator calculator = new Calculator(); // Act - wykonanie testowanej metody int result = calculator.add(2, 3); // Assert - sprawdzenie wyników Assertions.assertEquals(5, result); } } ===== Parametryzowane testy ===== * Parametryzowane testy - pozwalają na uruchomienie tej samej metody testowej z różnymi zestawami danych. * Adnotacja ''@ParameterizedTest'' - oznacza metodę jako parametryzowany test. * Źródła danych: * ''@ValueSource'' - pojedyncze wartości (np. liczby, stringi). * ''@CsvSource'' - dane w formacie CSV (np. "2,3,5"). * ''@MethodSource'' - dane dostarczane przez metodę zwracającą strumień argumentów. @ParameterizedTest @ValueSource(ints = {1, 2, 3}) public void testIsPositive(int number) { Assertions.assertTrue(number > 0); } ===== Mockito ===== * Mockito to framework do tworzenia mocków i stubów w testach jednostkowych. * Pozwala na izolację testowanej klasy od jej zależności. * Mock - obiekt zastępczy, który imituje zachowanie prawdziwego obiektu. * Stubbing - definiowanie zachowania mocka dla określonych wywołań metod. \\ ''when(mock.method()).thenReturn(value)'' - definiuje, co ma zwrócić mock dla danego wywołania. * Verify - sprawdzanie, czy określone metody zostały wywołane na mocku. \\ ''verify(mock).method()'' - sprawdza, czy metoda została wywołana. ===== Adnotacje Mockito ===== * ''@ExtendWith(MockitoExtension.class)'' - integracja z JUnit 5. * ''@Mock'' - tworzy atrapę (mock) dla danej klasy. * ''@InjectMocks'' - wstrzykuje mocki do testowanej klasy. * ''@Spy'' - tworzy częściowy mock, który zachowuje się jak prawdziwy obiekt, ale pozwala na stubbing i weryfikację. ===== Przykład ===== Test jednostkowy bez uruchamiania kontekstu Spring, z użyciem Mockito do mockowania zależności: @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test void shouldReturnUserWhenExists() { User user = new User(1L, "Jan"); when(userRepository.findById(1L)).thenReturn(Optional.of(user)); User result = userService.getById(1L); assertThat(result.getName()).isEqualTo("Jan"); } } ===== WebMvcTest ===== * ''@WebMvcTest'' - adnotacja do testowania warstwy webowej (kontrolerów) bez uruchamiania całego kontekstu Spring. * Pozwala na testowanie kontrolerów w izolacji, z mockowanymi zależnościami (serwisami). * Użycie ''MockMvc'' - narzędzie do symulowania żądań HTTP i sprawdzania odpowiedzi. * Metody: * ''perform()'' - wykonuje żądanie HTTP. * ''andExpect()'' - sprawdza oczekiwane wyniki (status, nagłówki, body). * ''jsonPath()'' - sprawdza zawartość JSON w odpowiedzi. * ''status().isOk()'' - sprawdza, czy status odpowiedzi to 200 OK. * ''content().string()'' - sprawdza zawartość odpowiedzi jako string. * ''jsonPath()'' - sprawdza zawartość odpowiedzi jako JSON. ===== Test kontrolera bez uruchamiania kontekstu Spring ===== Test kontrolera z użyciem ''@WebMvcTest'', który uruchamia tylko warstwę webową: @WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void shouldReturnUser() throws Exception { when(userService.getById(1L)).thenReturn(new User(1L, "Jan")); mockMvc.perform(get("/users/1")) .andExpect(status().isOk()) .andExpect(jsonPath("$.name").value("Jan")); } } ===== Test kontrolera z uruchomieniem kontekstu Spring ===== @SpringBootTest @AutoConfigureMockMvc class UserControllerTest { @Autowired private MockMvc mockMvc; @Test void shouldReturnUserList() throws Exception { mockMvc.perform(get("/users")) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].name").value("Jan")); } } ===== Test bazy danych ===== * ''@DataJpaTest'' - adnotacja do testowania warstwy dostępu do danych (repozytoriów) bez uruchamiania całego kontekstu Spring. * Użycie wbudowanej bazy danych H2 do testów, która jest automatycznie konfigurowana przez Spring Boot. * Testowanie encji, zapytań i operacji CRUD bez uruchamiania całej aplikacji. * ''spring-boot-starter-data-jpa-test'' - starter zawierający zależności do testowania JPA.' @DataJpaTest class UserRepositoryTest { @Autowired private UserRepository userRepository; @Test void shouldFindUserByEmail() { User user = new User(); user.setName("Jan"); user.setEmail("jan@test.pl"); userRepository.save(user); Optional result = userRepository.findByEmail("jan@test.pl"); assertThat(result).isPresent(); } } ===== Test integracyjny ===== * Testowanie współpracy między komponentami, uruchomienie kontekstu Spring. * Testowanie całej ścieżki od kontrolera, przez serwis, do repozytorium i bazy danych. @SpringBootTest class UserFlowIntegrationTest { @Autowired private UserService userService; @Test void shouldCreateUser() { User created = userService.create("Jan", "jan@test.pl"); assertThat(created.getId()).isNotNull(); } } ===== JavaDoc ===== * JavaDoc to narzędzie do generowania dokumentacji API z komentarzy w kodzie źródłowym. * Komentarze JavaDoc umieszczamy nad klasami, metodami i polami, używając specjalnej składni. * JavaDoc pozwala na tworzenie czytelnej i zrozumiałej dokumentacji dla programistów korzystających z naszego kodu. ===== Przykład komentarza JavaDoc ===== /** * Serwis odpowiedzialny za zarządzanie użytkownikami. */ public class UserService { /** * Zwraca użytkownika na podstawie identyfikatora. * * @param id identyfikator użytkownika * @return znaleziony użytkownik * @throws UserNotFoundException gdy użytkownik nie istnieje */ public User getById(Long id) { // ... return null; } } ===== Najważniejsze tagi JavaDoc ===== * ''@param'' - opisuje parametr metody * ''@return'' - opisuje wartość zwracaną przez metodę * ''@throws'' - opisuje wyjątki, które metoda może rzucić * ''@author'' - autor klasy lub metody * ''@version'' - wersja klasy lub metody * ''@see'' - odwołanie do innej klasy lub metody * ''@deprecated'' - oznacza, że element jest przestarzały ===== Dokumentacja ===== * [[https://docs.junit.org/6.1.0/overview.html|JUnit]] - oficjalna dokumentacja JUnit * [[https://site.mockito.org/|Mockito]] - framework do mockowania zależności w testach jednostkowych. * [[https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing|Spring Boot Test]] - wsparcie dla testów jednostkowych i integracyjnych. * [[https://www.geeksforgeeks.org/advance-java/spring-boot/|Spring Boot Tutorial]] * [[https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html|JavaDoc]] - oficjalna dokumentacja JavaDoc