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

Как относишься к тестам

1.0 Junior🔥 141 комментариев
#Soft Skills и карьера#Тестирование

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

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

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

# Мой подход к тестированию

Тестирование — это не просто обязанность, а основной инструмент качественной разработки. Вот мой профессиональный подход.

Философия тестирования

Для меня тесты — это:

1. Страховка от регрессии

Тесты защищают от простых ошибок при рефакторинге:

// Когда я меняю реализацию, тесты гарантируют, что поведение не изменилось
@Test
void testUserCreationIncrementCount() {
    // Arrange
    UserService service = new UserService();
    int initialCount = service.getUserCount();
    
    // Act
    service.createUser("John", "john@example.com");
    
    // Assert
    assertEquals(initialCount + 1, service.getUserCount());
}

Если я потом оптимизирую реализацию (например, меняю внутреннюю структуру), этот тест гарантирует корректность.

2. Документация кода

Тесты показывают, как код предполагается использовать:

// Из этого теста видно, что:
// - можно создать пользователя
// - нельзя создать пользователя с null email
// - повторное создание с тем же email возвращает старого пользователя

@Test
void testUserCreationVariations() {
    UserService service = new UserService();
    
    // Успешное создание
    User user = service.createUser("john@example.com");
    assertNotNull(user);
    
    // Null email
    assertThrows(IllegalArgumentException.class, 
        () -> service.createUser(null));
    
    // Повторное создание
    User same = service.createUser("john@example.com");
    assertEquals(user.id, same.id);  // Тот же пользователь
}

3. Инструмент проектирования (TDD)

Я часто использую Test-Driven Development при разработке:

// Шаг 1: Пишу тест (RED — падает)
@Test
void testCalculateMonthlyRevenue() {
    RevenueCalculator calculator = new RevenueCalculator();
    
    calculator.addOrder(new Order(100, "2024-01-15"));
    calculator.addOrder(new Order(50, "2024-01-20"));
    calculator.addOrder(new Order(75, "2024-02-10"));
    
    double january = calculator.calculateMonthlyRevenue("2024-01");
    assertEquals(150.0, january);
}

// Шаг 2: Пишу минимальный код (GREEN — проходит)
public class RevenueCalculator {
    private List<Order> orders = new ArrayList<>();
    
    public void addOrder(Order order) {
        orders.add(order);
    }
    
    public double calculateMonthlyRevenue(String month) {
        return orders.stream()
            .filter(o -> o.getDate().startsWith(month))
            .mapToDouble(Order::getAmount)
            .sum();
    }
}

// Шаг 3: Рефакторю (REFACTOR — остаётся GREEN)

Виды тестов и мой подход

Unit тесты (70% времени)

Тестирую отдельные компоненты:

@SpringBootTest
class UserRepositoryTests {
    @MockBean
    private EmailService emailService;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void testFindByEmail() {
        // Arrange
        User user = new User();
        user.setEmail("test@example.com");
        userRepository.save(user);
        
        // Act
        Optional<User> found = userRepository.findByEmail("test@example.com");
        
        // Assert
        assertTrue(found.isPresent());
        assertEquals(user.id, found.get().id);
    }
}

Integration тесты (20% времени)

Тестирую взаимодействие компонентов:

@SpringBootTest
class UserServiceIntegrationTests {
    @Autowired
    private UserService userService;
    
    @Autowired
    private EmailService emailService;
    
    @Test
    void testUserCreationSendsEmail() {
        // Arrange
        User user = new User("john@example.com", "John");
        
        // Act
        User created = userService.createUser(user);
        
        // Assert
        verify(emailService).sendWelcomeEmail("john@example.com");
        assertEquals("john@example.com", created.getEmail());
    }
}

E2E тесты (10% времени)

Тестирую полные сценарии через API:

@SpringBootTest(webEnvironment = RANDOM_PORT)
class UserApiE2ETests {
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void testCompleteUserJourney() {
        // 1. Регистрация
        var register = restTemplate.postForObject(
            "/api/users/register",
            new RegisterRequest("john@example.com", "password123"),
            User.class
        );
        assertNotNull(register);
        
        // 2. Логин
        var login = restTemplate.postForObject(
            "/api/auth/login",
            new LoginRequest("john@example.com", "password123"),
            LoginResponse.class
        );
        assertNotNull(login.getToken());
        
        // 3. Получение профиля
        var headers = new HttpHeaders();
        headers.setBearerAuth(login.getToken());
        var profile = restTemplate.exchange(
            "/api/users/me",
            GET,
            new HttpEntity<>(headers),
            User.class
        );
        assertEquals("john@example.com", profile.getBody().getEmail());
    }
}

Лучшие практики, которые я соблюдаю

1. Arrange-Act-Assert (AAA)

@Test
void testPaymentProcessing() {
    // Arrange — подготовка данных
    Payment payment = new Payment(100.0, "USD");
    PaymentProcessor processor = new PaymentProcessor();
    
    // Act — выполнение
    PaymentResult result = processor.process(payment);
    
    // Assert — проверка результата
    assertTrue(result.isSuccess());
    assertEquals("USD", result.getCurrency());
}

2. One assertion per test (когда возможно)

// ❌ Плохо — много проверок
@Test
void testUser() {
    User user = createUser();
    assertEquals("John", user.getName());
    assertEquals(25, user.getAge());
    assertNotNull(user.getEmail());
}

// ✅ Хорошо — одна проверка
@Test
void testUserHasCorrectName() {
    User user = createUser();
    assertEquals("John", user.getName());
}

3. Мокирование внешних зависимостей

@Test
void testOrderCreationCallsPaymentGateway() {
    // Mock внешний сервис
    PaymentGateway gatewayMock = mock(PaymentGateway.class);
    when(gatewayMock.charge(anyDouble()))
        .thenReturn(new ChargeResult("success", "txn_123"));
    
    OrderService orderService = new OrderService(gatewayMock);
    
    // Act
    Order order = orderService.createOrder(new Order(99.99));
    
    // Assert
    verify(gatewayMock).charge(99.99);
    assertTrue(order.isPaid());
}

4. Параметризованные тесты

@ParameterizedTest
@CsvSource({
    "admin,     true",   // email, isValid
    "user@test, false",
    "test@example.com, true"
})
void testEmailValidation(String email, boolean expectedValid) {
    EmailValidator validator = new EmailValidator();
    assertEquals(expectedValid, validator.isValid(email));
}

Когда я НЕ пишу тесты

Буду честен — не всё нужно тестировать:

// ❌ Не тестирую очевидные getters/setters
public class User {
    private String email;
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

// ❌ Не тестирую конфигурацию Spring (она проверяется при запуске)
@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() { ... }
}

// ❌ Не тестирую код третьих библиотек (они уже протестированы)

Мой опыт с тестами

За 10+ лет разработки я понял:

  1. Тесты экономят время — удобнее писать тесты, чем вручную проверять одно и то же 100 раз

  2. Хорошие тесты — ценнее, чем хороший код — плохой код с хорошими тестами можно рефакторить. Хороший код без тестов становится хрупким

  3. 100% coverage — не цель — цель — тестировать критичный код. Coverage 70-85% обычно хороший баланс

  4. Тесты требуют навыков — писать быстрые, понятные, не-flaky тесты — это отдельное мастерство

  5. TDD работает — когда пишу тесты сначала, код получается чище и легче тестировать

Резюме

Тестирование для меня — это не обязанность, а инструмент качества и скорости разработки. Я пишу тесты потому что:

  • Они дают уверенность при изменении кода
  • Они служат документацией
  • Они ловят баги на ранних стадиях
  • Они помогают проектировать лучший код

Я ищу баланс между полнотой тестирования и скоростью разработки, и всегда готов объяснить, какие части кода нужно тестировать и почему.

Как относишься к тестам | PrepBro