Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды тестирования в Java разработке
Тестирование — это критически важная часть разработки. Я использую многоуровневый подход к тестированию, где каждый уровень решает свои задачи и имеет свои инструменты.
1. Unit тестирование (модульное)
Unit тесты проверяют отдельные функции и методы в изоляции. Это самая быстрая и дешёвая форма тестирования.
Инструменты:
- JUnit 5 — стандартный фреймворк
- Mockito — создание mock-объектов для изоляции
- AssertJ — удобные assertion'ы
public class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void testAddition_shouldReturnCorrectSum() {
// Arrange
int a = 5;
int b = 3;
// Act
int result = calculator.add(a, b);
// Assert
assertThat(result).isEqualTo(8);
}
@Test
void testDivisionByZero_shouldThrowException() {
assertThatThrownBy(() -> calculator.divide(10, 0))
.isInstanceOf(ArithmeticException.class)
.hasMessage("Division by zero");
}
}
2. Интеграционное тестирование
Integration тесты проверяют взаимодействие нескольких компонентов. Они медленнее unit-тестов, но проверяют реальные сценарии.
Типичные сценарии:
- Работа с базой данных
- Работа с external API
- Работа с очередями сообщений
@SpringBootTest
@AutoConfigureMockMvc
public class UserServiceIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Test
void testCreateUser_shouldPersistInDatabase() throws Exception {
// Arrange
UserCreateRequest request = new UserCreateRequest(
"john@example.com",
"John Doe"
);
// Act
MvcResult result = mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andReturn();
// Assert
String userId = extractUserIdFromResponse(result);
User savedUser = userRepository.findById(userId).orElseThrow();
assertThat(savedUser.getEmail()).isEqualTo("john@example.com");
}
}
3. E2E (сквозное) тестирование
End-to-End тесты проверяют весь процесс от пользовательского интерфейса до базы данных. Они самые медленные, но проверяют полные сценарии работы.
Инструменты:
- Selenium — для тестирования веб-приложений
- TestNG — альтернатива JUnit
- Cucumber — BDD фреймворк для написания тестов на языке бизнеса
public class LoginE2ETest {
private WebDriver driver;
@BeforeEach
void setUp() {
driver = new ChromeDriver();
driver.get("http://localhost:8080");
}
@Test
void testLoginFlow_userCanLoginWithValidCredentials() {
// Navigate to login page
WebElement loginLink = driver.findElement(By.id("login-link"));
loginLink.click();
// Fill login form
WebElement emailField = driver.findElement(By.id("email"));
emailField.sendKeys("user@example.com");
WebElement passwordField = driver.findElement(By.id("password"));
passwordField.sendKeys("password123");
WebElement submitButton = driver.findElement(By.id("submit"));
submitButton.click();
// Assert user is logged in
WebElement userProfile = driver.findElement(By.id("user-profile"));
assertThat(userProfile.isDisplayed()).isTrue();
}
@AfterEach
void tearDown() {
driver.quit();
}
}
4. Performance тестирование
Performance тесты проверяют скорость выполнения и нагрузкоспособность приложения.
Инструменты:
- JMH (Java Microbenchmark Harness) — для микробенчмарков
- Apache JMeter — для нагрузочного тестирования
- Gatling — для современного нагрузочного тестирования
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class StringConcatenationBenchmark {
@Benchmark
public String concatenateWithPlus() {
String result = "";
for (int i = 0; i < 1000; i++) {
result += "x";
}
return result;
}
@Benchmark
public String concatenateWithStringBuilder() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < 1000; i++) {
result.append("x");
}
return result.toString();
}
}
5. Нагрузочное тестирование (Load Testing)
Load тесты проверяют поведение системы при большом количестве одновременных пользователей.
public class LoadTestExample {
@Test
public void testApplicationUnderLoad() {
int numberOfThreads = 100;
int numberOfRequests = 10000;
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
CountDownLatch latch = new CountDownLatch(numberOfRequests);
long startTime = System.currentTimeMillis();
for (int i = 0; i < numberOfRequests; i++) {
executor.submit(() -> {
try {
// Simulate API call
simulateRequest();
} finally {
latch.countDown();
}
});
}
latch.await();
long duration = System.currentTimeMillis() - startTime;
System.out.println("Processed " + numberOfRequests + " requests in " + duration + "ms");
executor.shutdown();
}
}
6. Security тестирование
Security тесты проверяют защиту приложения от уязвимостей.
@SpringBootTest
public class SecurityTest {
@Autowired
private MockMvc mockMvc;
@Test
void testUnauthorizedAccessIsDenied() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isUnauthorized());
}
@Test
void testCSRFProtection() throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isForbidden());
}
}
Пирамида тестирования (Testing Pyramid)
/\\ E2E тесты (10%)
/ \\ Медленные, дорогие, нестабильные
/ \\
/ \\ Integration тесты (20%)
/ \\ Средней скорости, проверяют интеграцию
/ \\
/__________\\ Unit тесты (70%)
Быстрые, дешёвые, стабильные
Практический пример комплексного тестирования
@SpringBootTest
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@MockBean
private PaymentService paymentService;
@Test
void testOrderCreation_completesSuccessfully() {
// Unit + Integration
Order order = Order.builder()
.items(List.of(new Item("SKU123", 2)))
.build();
when(paymentService.charge(any()))
.thenReturn(PaymentResult.success());
Order savedOrder = orderService.createOrder(order);
assertThat(savedOrder.getId()).isNotNull();
assertThat(savedOrder.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
verify(paymentService).charge(any());
}
}
Выводы и best practices
Стратегия покрытия:
- Unit тесты — 70% (быстрые и дешёвые)
- Integration тесты — 20% (критичные сценарии)
- E2E тесты — 10% (только ключевые workflows)
Ключевые принципы:
- Каждый тест должен проверять одно поведение
- Используй AAA паттерн (Arrange-Act-Assert)
- Тесты должны быть независимыми друг от друга
- Мокируй external dependencies для unit-тестов
- Тесты — это документация кода