~~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