Какие знаешь тесты для реализации Test-Driven Development?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды тестов в 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 — гарантируют, что система работает целиком. Правильный баланс между разными типами тестов — ключ к качественному коду и быстрой разработке.