Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
На чем писал тест кейсы
Общий подход к тестированию
В современном Java проекте используется многоуровневая стратегия тестирования с разными инструментами для каждого уровня. Это гарантирует качество на всех этапах разработки.
1. Unit тесты: JUnit 5 + Mockito
JUnit 5 (Jupiter) - это основа для модульного тестирования:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
class OrderServiceTest {
private OrderService orderService;
private OrderRepository orderRepository;
@BeforeEach
void setUp() {
orderService = new OrderService();
orderRepository = mock(OrderRepository.class);
}
@Test
void shouldCreateOrder() {
// Arrange
Order order = new Order("user123", 100.0);
when(orderRepository.save(order)).thenReturn(order);
// Act
Order result = orderService.createOrder(order);
// Assert
assertNotNull(result);
assertEquals(order.getId(), result.getId());
verify(orderRepository).save(order);
}
}
Mockito для мокирования зависимостей:
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class PaymentServiceTest {
@Mock
private PaymentGateway paymentGateway;
@InjectMocks
private PaymentService paymentService;
@Test
void shouldProcessPayment() {
when(paymentGateway.charge(100.0)).thenReturn("success");
String result = paymentService.processPayment(100.0);
assertEquals("success", result);
}
}
2. Integration тесты: TestContainers + Spring Test
TestContainers для поднятия БД в Docker контейнерах:
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
class OrderRepositoryIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("test_db")
.withUsername("test")
.withPassword("test");
@Autowired
private OrderRepository orderRepository;
@Test
void shouldPersistAndRetrieveOrder() {
Order order = new Order("user123", 100.0);
Order saved = orderRepository.save(order);
Order retrieved = orderRepository.findById(saved.getId()).orElse(null);
assertNotNull(retrieved);
assertEquals("user123", retrieved.getUserId());
}
}
Spring Boot Test для интеграции со Spring контекстом:
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
class OrderControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldGetOrderById() throws Exception {
mockMvc.perform(get("/api/orders/123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value("123"))
.andExpect(jsonPath("$.status").value("COMPLETED"));
}
@Test
void shouldCreateOrder() throws Exception {
String orderJson = "{\"userId\":\"user123\",\"amount\":100.0}";
mockMvc.perform(post("/api/orders")
.contentType(MediaType.APPLICATION_JSON)
.content(orderJson))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").exists());
}
}
3. Kafka тесты: EmbeddedKafka
Для тестирования асинхронных сообщений:
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.EmbeddedKafkaBroker;
@SpringBootTest
@EmbeddedKafka(partitions = 1, brokerProperties = {
"listeners=PLAINTEXT://localhost:9092"
})
class OrderEventProducerTest {
@Autowired
private OrderEventProducer orderEventProducer;
@Autowired
private KafkaTemplate<String, OrderEvent> kafkaTemplate;
@Test
void shouldPublishOrderCreatedEvent() throws Exception {
OrderEvent event = new OrderEvent("order123", "user123");
orderEventProducer.publishOrderCreated(event);
// Проверяем, что сообщение попало в Kafka
ConsumerRecord<String, OrderEvent> record =
kafkaTestUtils.getSingleRecord(kafkaBroker, "order-events");
assertEquals("user123", record.key());
assertEquals("order123", record.value().getOrderId());
}
}
4. E2E тесты: Selenium / Playwright
Selenium для старых проектов:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
class OrderCreationE2ETest {
private WebDriver driver;
@BeforeEach
void setUp() {
driver = new ChromeDriver();
driver.get("http://localhost:3000");
}
@Test
void shouldCreateOrderFromUI() {
driver.findElement(By.id("create-order-btn")).click();
driver.findElement(By.name("amount")).sendKeys("100");
driver.findElement(By.xpath("//button[contains(text(), 'Submit')]")).click();
WebElement successMessage = driver.findElement(By.className("success"));
assertTrue(successMessage.isDisplayed());
assertTrue(driver.getCurrentUrl().contains("/orders/"));
}
@AfterEach
void tearDown() {
driver.quit();
}
}
Playwright для современных проектов:
import com.microsoft.playwright.*;
class OrderCreationPlaywrightTest {
private Browser browser;
private Page page;
@BeforeEach
void setUp() {
browser = Playwright.create().chromium().launch();
page = browser.newContext().newPage();
page.navigate("http://localhost:3000");
}
@Test
void shouldCreateOrderFromUI() {
page.click("button:has-text('Create Order')");
page.fill("input[name='amount']", "100");
page.click("button:has-text('Submit')");
page.waitForNavigation();
String url = page.url();
assertTrue(url.contains("/orders/"));
}
@AfterEach
void tearDown() {
browser.close();
}
}
5. Performance тесты: JMH
JMH (Java Microbenchmark Harness) для тестирования производительности:
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class OrderProcessingBenchmark {
private OrderService orderService;
private Order order;
@Setup
public void setup() {
orderService = new OrderService();
order = new Order("user123", 100.0);
}
@Benchmark
public void testOrderProcessing() {
orderService.processOrder(order);
}
}
6. Contract тесты: Pact / Spring Cloud Contract
Для тестирования взаимодействия микросервисов:
import au.com.dius.pact.consumer.dsl.PactBuilder;
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
@ExtendWith(PactConsumerTestExt.class)
class OrderServiceContractTest {
@Pact(provider = "UserService", consumer = "OrderService")
public V4Pact createPact(PactBuilder builder) {
return builder
.given("user with id 123 exists")
.uponReceiving("a request for user details")
.path("/api/users/123")
.method("GET")
.willRespondWith()
.status(200)
.body(Map.of(
"id", "123",
"name", "John Doe"
))
.toPact();
}
}
7. Структура тестов в проекте
src/
├── main/
│ ├── java/
│ │ └── com/company/order/
│ │ ├── domain/
│ │ ├── application/
│ │ └── infrastructure/
│ └── resources/
└── test/
├── java/
│ └── com/company/order/
│ ├── unit/
│ │ ├── domain/
│ │ ├── application/
│ │ └── infrastructure/
│ ├── integration/
│ └── e2e/
└── resources/
├── application-test.yml
└── test-data.sql
8. Maven/Gradle конфигурация
<dependencies>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.1</version>
<scope>test</scope>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<!-- TestContainers -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.17.6</version>
<scope>test</scope>
</dependency>
</dependencies>
9. Best Practices для тестов
AAA паттерн (Arrange-Act-Assert):
@Test
void shouldCalculateTotalPrice() {
// Arrange - подготовка данных
Order order = new Order();
order.addItem(new OrderItem("item1", 10.0, 2));
// Act - выполнение
double total = order.calculateTotal();
// Assert - проверка
assertEquals(20.0, total);
}
Given-When-Then (BDD стиль):
@Test
void givenActiveUser_whenCreatingOrder_thenOrderIsCreated() {
// Given
User user = createActiveUser();
// When
Order order = orderService.createOrder(user, 100.0);
// Then
assertNotNull(order);
assertEquals(user.getId(), order.getUserId());
}
10. Coverage требования
Целевое покрытие: 80-90%
<!-- pom.xml для JaCoCo -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
Запуск тестов с отчётом:
mvn clean test jacoco:report
open target/site/jacoco/index.html
Резюме инструментов
| Уровень | Инструмент | Назначение |
|---|---|---|
| Unit | JUnit 5 + Mockito | Тестирование классов |
| Integration | Spring Boot Test + TestContainers | Тестирование с БД |
| API | MockMvc, RestAssured | Тестирование REST |
| Event Streaming | EmbeddedKafka | Тестирование Kafka |
| UI/E2E | Selenium, Playwright | Тестирование фронта |
| Performance | JMH | Микробенчмарки |
| Contract | Pact, Spring Cloud Contract | Тестирование API контрактов |
Вывод
Это полнофункциональный стек тестирования, который обеспечивает качество на всех уровнях приложения: от модульного уровня до полных E2E сценариев. Такой подход гарантирует надёжность production приложений и даёт уверенность при рефакторинге кода.