← Назад к вопросам

Какие сценарии тестирования проверял

2.0 Middle🔥 151 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие сценарии тестирования проверял?

В профессиональной разработке на Java мы проверяем множество сценариев тестирования, используя различные уровни тестирования (unit, integration, end-to-end) и разные подходы к тестированию. Вот основные сценарии и практики, которые я применял:

1. Unit тестирование (JUnit + Mockito)

Тестирование успешных случаев

@Test
public void testCalculateTaxForValidIncome() {
    // Arrange
    TaxCalculator calculator = new TaxCalculator();
    double income = 50000.0;
    double expectedTax = 10000.0; // 20% tax
    
    // Act
    double actualTax = calculator.calculateTax(income);
    
    // Assert
    assertEquals(expectedTax, actualTax, 0.01);
}

Тестирование граничных значений (Boundary Testing)

@Test
public void testWithZeroIncome() {
    TaxCalculator calculator = new TaxCalculator();
    assertEquals(0.0, calculator.calculateTax(0.0), 0.01);
}

@Test
public void testWithMaximumIncome() {
    TaxCalculator calculator = new TaxCalculator();
    double maxIncome = Double.MAX_VALUE;
    // Проверяем, что не выбросится исключение
    assertDoesNotThrow(() -> calculator.calculateTax(maxIncome));
}

Тестирование исключений

@Test
public void testNegativeIncomeThrowsException() {
    TaxCalculator calculator = new TaxCalculator();
    
    // Assert что будет выброшено исключение
    assertThrows(IllegalArgumentException.class, () -> {
        calculator.calculateTax(-1000.0);
    });
}

@Test
public void testNullInputThrowsNullPointerException() {
    UserService service = new UserService();
    
    assertThrows(NullPointerException.class, () -> {
        service.createUser(null);
    });
}

Тестирование с Mockito (мокирование зависимостей)

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @Mock
    private EmailService emailService;
    
    @InjectMocks
    private UserService userService; // Инъектируем моки
    
    @Test
    public void testCreateUserSendsWelcomeEmail() {
        // Arrange
        User newUser = new User("john@example.com");
        when(userRepository.save(any(User.class))).thenReturn(newUser);
        
        // Act
        userService.createUser(newUser);
        
        // Assert
        verify(emailService, times(1)).sendWelcomeEmail(newUser.getEmail());
        verify(userRepository, times(1)).save(newUser);
    }
}

2. Integration тестирование

Тестирование с реальной БД

@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    @Transactional
    public void testCreateUserThroughAPI() throws Exception {
        String userJson = "{\"email\": \"test@example.com\", \"name\": \"John\"}
";
        
        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(userJson))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.email").value("test@example.com"));
        
        // Проверяем, что пользователь действительно сохранён в БД
        User savedUser = userRepository.findByEmail("test@example.com");
        assertNotNull(savedUser);
        assertEquals("John", savedUser.getName());
    }
}

Тестирование сценариев с несколькими операциями

@SpringBootTest
public class OrderProcessingIntegrationTest {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Test
    @Transactional
    public void testCompleteOrderProcessing() {
        // 1. Проверяем наличие товара
        assertTrue(inventoryService.isAvailable("PRODUCT_123", 5));
        
        // 2. Создаём заказ
        Order order = orderService.createOrder("USER_1", "PRODUCT_123", 5);
        assertNotNull(order.getId());
        
        // 3. Проверяем платёж
        PaymentResult payment = paymentService.processPayment(order);
        assertTrue(payment.isSuccessful());
        
        // 4. Уменьшаем инвентарь
        inventoryService.decreaseStock("PRODUCT_123", 5);
        
        // 5. Проверяем финальное состояние
        Order completedOrder = orderService.getOrder(order.getId());
        assertEquals(OrderStatus.COMPLETED, completedOrder.getStatus());
        assertEquals(0, inventoryService.getStock("PRODUCT_123"));
    }
}

3. Параметризованное тестирование (Parameterized Tests)

public class MathOperationsTest {
    
    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3, 4, 5})
    public void testIsPositive(int number) {
        assertTrue(number > 0);
    }
    
    @ParameterizedTest
    @CsvSource({
        "10, 5, 15",   // add(10, 5) = 15
        "0, 0, 0",      // add(0, 0) = 0
        "-5, 5, 0",     // add(-5, 5) = 0
        "100, -50, 50"  // add(100, -50) = 50
    })
    public void testAdditionWithMultipleInputs(int a, int b, int expected) {
        Calculator calc = new Calculator();
        assertEquals(expected, calc.add(a, b));
    }
    
    @ParameterizedTest
    @MethodSource("provideTestData")
    public void testWithComplexData(String input, String expected) {
        assertEquals(expected, processInput(input));
    }
    
    private static Stream<Arguments> provideTestData() {
        return Stream.of(
            Arguments.of("hello", "HELLO"),
            Arguments.of("world", "WORLD"),
            Arguments.of("", "")
        );
    }
}

4. Тестирование обработки ошибок и исключений

@Test
public void testDataValidationScenarios() {
    UserValidator validator = new UserValidator();
    
    // Пустое имя
    ValidationResult result1 = validator.validate(new User("", "test@example.com"));
    assertFalse(result1.isValid());
    assertTrue(result1.getErrors().contains("Name cannot be empty"));
    
    // Неправильный email
    ValidationResult result2 = validator.validate(new User("John", "invalid-email"));
    assertFalse(result2.isValid());
    assertTrue(result2.getErrors().contains("Invalid email format"));
}

@Test
public void testConcurrentAccessScenario() throws InterruptedException {
    AtomicInteger counter = new AtomicInteger(0);
    CountDownLatch latch = new CountDownLatch(10);
    
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            counter.incrementAndGet();
            latch.countDown();
        }).start();
    }
    
    latch.await();
    assertEquals(10, counter.get());
}

5. Тестирование REST API

@SpringBootTest
@AutoConfigureMockMvc
public class UserAPITest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testGetUserByIdSuccess() throws Exception {
        mockMvc.perform(get("/api/users/1")
                .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.name").exists());
    }
    
    @Test
    public void testGetUserByIdNotFound() throws Exception {
        mockMvc.perform(get("/api/users/999")
                .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isNotFound());
    }
    
    @Test
    public void testCreateUserValidation() throws Exception {
        String invalidUserJson = "{\"name\": \"\"}";
        
        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(invalidUserJson))
            .andExpect(status().isBadRequest());
    }
}

6. Тестирование многопоточности и Race Conditions

public class ThreadSafetyTest {
    
    @Test
    public void testConcurrentListModification() throws InterruptedException {
        List<Integer> list = Collections.synchronizedList(new ArrayList<>());
        int threadCount = 100;
        CountDownLatch latch = new CountDownLatch(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            final int value = i;
            new Thread(() -> {
                list.add(value);
                latch.countDown();
            }).start();
        }
        
        latch.await();
        assertEquals(threadCount, list.size());
    }
    
    @Test
    public void testDeadlockScenario() throws InterruptedException {
        Object lock1 = new Object();
        Object lock2 = new Object();
        
        AtomicBoolean completed = new AtomicBoolean(false);
        
        Thread t1 = new Thread(() -> {
            synchronized(lock1) {
                try { Thread.sleep(10); } catch (InterruptedException e) {}
                synchronized(lock2) {
                    completed.set(true);
                }
            }
        });
        
        Thread t2 = new Thread(() -> {
            synchronized(lock2) {
                try { Thread.sleep(10); } catch (InterruptedException e) {}
                synchronized(lock1) {
                    completed.set(true);
                }
            }
        });
        
        t1.start();
        t2.start();
        
        // Ждём с таймаутом (deadlock не произойдёт, если код правильный)
        t1.join(1000);
        t2.join(1000);
        
        assertFalse(t1.isAlive());
        assertFalse(t2.isAlive());
    }
}

7. Тестирование производительности

@Test
public void testAlgorithmPerformance() {
    List<Integer> largeList = new ArrayList<>();
    for (int i = 0; i < 1_000_000; i++) {
        largeList.add(i);
    }
    
    long startTime = System.currentTimeMillis();
    
    // Функция, которую тестируем
    int result = largeList.stream()
        .filter(n -> n % 2 == 0)
        .mapToInt(Integer::intValue)
        .sum();
    
    long endTime = System.currentTimeMillis();
    long duration = endTime - startTime;
    
    // Должно выполниться менее чем за 1 секунду
    assertTrue(duration < 1000, "Algorithm took too long: " + duration + "ms");
}

8. Тестирование состояния (State Testing)

public class StateMachineTest {
    
    @Test
    public void testOrderStateTransitions() {
        Order order = new Order();
        assertEquals(OrderState.PENDING, order.getState());
        
        // Переход 1: PENDING → CONFIRMED
        order.confirm();
        assertEquals(OrderState.CONFIRMED, order.getState());
        
        // Переход 2: CONFIRMED → SHIPPED
        order.ship();
        assertEquals(OrderState.SHIPPED, order.getState());
        
        // Переход 3: SHIPPED → DELIVERED
        order.deliver();
        assertEquals(OrderState.DELIVERED, order.getState());
        
        // Нельзя перейти в CONFIRMED из DELIVERED
        assertThrows(IllegalStateException.class, order::confirm);
    }
}

9. Сценарии с VCR (запись HTTP запросов)

@ExtendWith(VcrExtension.class)
@Cassette("src/test/resources/cassettes/github_api.yaml")
public class ExternalAPITest {
    
    @Test
    public void testGitHubAPICall() {
        GitHubClient client = new GitHubClient();
        
        // При первом запуске — реальный запрос, записывается в cassette
        // При последующих запусках — используется записанный ответ
        Repository repo = client.getRepository("torvalds", "linux");
        
        assertNotNull(repo);
        assertEquals("linux", repo.getName());
    }
}

10. Coverage и контроль качества

# Запуск тестов с отчётом о покрытии
mvn clean test jacoco:report

# JaCoCo требует минимум 80-90% покрытия
# Проверяем в CI/CD pipeline

Итоговое резюме тестовых сценариев

ТипПримерыИнструменты
UnitБизнес-логика, валидацияJUnit, Mockito
IntegrationAPI, БД, сервисыTestContainers, MockMvc
E2EПолный user flowSelenium, Playwright
PerformanceНагрузочное тестированиеJMH, Gatling
SecuritySQL Injection, CSRFOWASP ZAP, JWTk
BoundaryГраничные значенияParameterized tests
ExceptionОбработка ошибокassertThrows
ConcurrencyМногопоточностьCountDownLatch, Thread

В профессиональной разработке на Java мы используем эти сценарии комплексно для обеспечения высокого качества кода.