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

Какие знаешь тесты для реализации Test-Driven Development?

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

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

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

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

Виды тестов в Test-Driven Development

Test-Driven Development (TDD) — это методология разработки, в которой тесты пишутся ДО написания кода. Цикл TDD состоит из трёх фаз: RED (падающий тест), GREEN (минимальный код) и REFACTOR (улучшение). Для эффективной реализации TDD нужно понимать различные типы тестов и их роли.

1. Unit-тесты (Модульные тесты)

Тестируют отдельные методы или классы в изоляции. Это основной тип тестов в TDD.

// Сначала пишем тест
@Test
public void testCalculatorAdd() {
    Calculator calculator = new Calculator();
    int result = calculator.add(2, 3);
    assertEquals(5, result);
}

// Потом реализуем минимальный код
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

Характеристики:

  • Быстрые (миллисекунды)
  • Независимые друг от друга
  • Не требуют внешних ресурсов
  • Используют JUnit (Java стандарт)

Пример использования Mockito для изоляции:

@Test
public void testUserServiceSaveUser() {
    // Arrange
    UserRepository mockRepo = mock(UserRepository.class);
    UserService service = new UserService(mockRepo);
    
    // Act
    service.saveUser(new User("John"));
    
    // Assert
    verify(mockRepo).save(any(User.class));
}

2. Integration Tests (Интеграционные тесты)

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

@SpringBootTest
@Transactional
public class UserRepositoryIntegrationTest {
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void testSaveAndFindUser() {
        // Arrange
        User user = new User("Alice", "alice@example.com");
        
        // Act
        User saved = userRepository.save(user);
        User found = userRepository.findById(saved.getId()).orElse(null);
        
        // Assert
        assertNotNull(found);
        assertEquals("Alice", found.getName());
    }
}

Характеристики:

  • Медленнее unit-тестов
  • Требуют реальной БД или контейнеров
  • Тестируют реальное поведение системы
  • Помогают выявить проблемы в интеграции

3. End-to-End (E2E) тесты

Тестируют полный поток через весь стек приложения от UI до БД.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerE2ETest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testCreateUserThroughAPI() {
        // Arrange
        User newUser = new User("Bob", "bob@example.com");
        
        // Act
        ResponseEntity<User> response = restTemplate.postForEntity(
            "/api/users", newUser, User.class
        );
        
        // Assert
        assertEquals(HttpStatus.CREATED, response.getStatusCode());
        assertEquals("Bob", response.getBody().getName());
    }
}

Характеристики:

  • Самые медленные
  • Тестируют реальные HTTP запросы и ответы
  • Самые дорогие в разработке и поддержке
  • Критичны для функциональной корректности

4. Acceptance Tests (Приёмочные тесты)

Тестируют требования бизнеса на языке, понятном non-technical stakeholders. Часто используют BDD frameworks вроде Cucumber.

# features/user.feature
Feature: User Management
  Scenario: Create a new user
    Given the system has no users
    When I create a user with email "john@example.com"
    Then the user should be saved successfully
    And I should receive a confirmation email
@Given("the system has no users")
public void systemHasNoUsers() {
    userRepository.deleteAll();
}

@When("I create a user with email {string}")
public void createUserWithEmail(String email) {
    this.user = new User(email);
    this.result = userService.createUser(user);
}

@Then("the user should be saved successfully")
public void userShouldBeSavedSuccessfully() {
    assertTrue(result.isSuccess());
}

5. Contract Tests (Тесты контрактов)

Проверяют, что микросервисы или компоненты взаимодействуют согласно ожидаемому контракту. Часто используют Pact или Spring Cloud Contract.

@RunWith(PactRunner.class)
@PactBroker
public class UserServiceContractTest {
    @Pact(consumer = "UserUI", provider = "UserService")
    public RequestResponsePact createGetUserPact(PactDslWithProvider builder) {
        return builder
            .given("user with id 123 exists")
            .uponReceiving("a request for user 123")
            .path("/api/users/123")
            .method("GET")
            .willRespondWith()
            .status(200)
            .body(JsonBody.newJsonBody((root) -> {
                root.stringType("name", "John");
            }).build())
            .toPact();
    }
}

6. Performance Tests (Тесты производительности)

Проверяют скорость и нагрузостойкость системы.

@Test
@Timeout(5) // TimeUnit.SECONDS
public void testCalculatorPerformance() {
    Calculator calculator = new Calculator();
    
    long startTime = System.nanoTime();
    for (int i = 0; i < 1_000_000; i++) {
        calculator.add(1, 1);
    }
    long duration = System.nanoTime() - startTime;
    
    assertTrue(duration < 1_000_000_000); // < 1 секунды
}

Пирамида тестирования в TDD

        /\  
       /  \  E2E тесты (10%)
      /----\
     /      \  Integration (20%)
    /--------\
   /          \  Unit тесты (70%)
  /____________\

Лучшая практика: большинство тестов должны быть unit-тесты (быстрые и дешёвые), меньше интеграционных, и совсем мало E2E.

TDD цикл с примером

Шаг 1: RED — Пишем падающий тест

@Test
public void testStringReversal() {
    String result = StringUtils.reverse("hello");
    assertEquals("olleh", result);
}
// Тест падает: метод не существует

Шаг 2: GREEN — Пишем минимальный код

public class StringUtils {
    public static String reverse(String input) {
        return new StringBuilder(input).reverse().toString();
    }
}
// Тест проходит

Шаг 3: REFACTOR — Улучшаем код

public class StringUtils {
    public static String reverse(String input) {
        if (input == null || input.isEmpty()) return input;
        return new StringBuilder(input).reverse().toString();
    }
}
// Тесты всё ещё проходят, код более робастный

Инструменты для TDD в Java

  • JUnit 5 — основной framework для unit-тестов
  • Mockito — для создания mock-объектов
  • TestNG — альтернатива JUnit
  • Cucumber — для BDD/acceptance tests
  • JMeter — для load testing
  • Pact — для contract testing
  • AssertJ — для удобных assertions

Выводы

Основной закон TDD: тест первым, код вторым. Unit-тесты — базис пирамиды, они дешёвые и быстрые. Интеграционные тесты — проверяют взаимодействие, E2E — гарантируют, что система работает целиком. Правильный баланс между разными типами тестов — ключ к качественному коду и быстрой разработке.