Как стать автором
Обновить
607.15
OTUS
Цифровые навыки от ведущих экспертов

5 лайфхаков по тестированию для новичков, которые экономят до 100 часов в месяц

Время на прочтение6 мин
Количество просмотров1K

Автор статьи: Сергей Прощаев (@sproshchaev), Руководитель направления Java‑разработки в FinTech

Введение: Зачем тестировать код, если он «и так работает»?

Представьте, что вы — повар в ресторане. Вы приготовили новое блюдо, но не пробуете его перед подачей гостю. Результат? Клиент может отравиться или остаться недоволен вкусом. Точно так же в программировании: без проверки код может содержать ошибки, которые проявятся в самый неподходящий момент. Unit‑тесты — это как дегустация блюда перед подачей. Они проверяют отдельные части кода (методы, классы) на корректность, чтобы вы были уверены: всё работает так, как задумано.

1. Что такое Unit‑тест? Пример из жизни

Допустим, вы пишете класс Calculator с методом divide(int a, int b), который делит два числа:

public class Calculator {
    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("Нельзя делить на ноль!");
        }
        return a / b;
    }
}

Как убедиться, что метод не только считает правильно, но и обрабатывает деление на ноль? Надо создать тест, который будет проверять какие параметры поступают на вход этого метода и что этот метод возвращает.

Все тесты, которые вы добавляете в приложение должны лежать в папке src/test/java.

Пример теста для метода divide():

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

public class CalculatorTest {

    @Test
    void testDivide_Success() {
        Calculator calc = new Calculator();
        assertEquals(2, calc.divide(10, 5));
    }

    @Test
    void testDivide_ByZero() {
        Calculator calc = new Calculator();
        Exception exception = assertThrows(IllegalArgumentException.class, () -> {
            calc.divide(10, 0);
        });
        assertEquals("Нельзя делить на ноль!", exception.getMessage());
    }
}

Что здесь происходит?

  • @Test — аннотация, которая помечает метод как тест.

  • assertEquals() проверяет, что результат совпадает с ожидаемым.

  • assertThrows() ловит исключение, если делитель равен нулю.

Чтобы запустить эти тесты, нужно подключить JUnit 5 в ваш проект. JUnit 5 — стандартный фреймворк для тестирования в Java. Вот как это сделать через Maven в файле pom.xml:

<dependencies>
    <!-- JUnit 5 (основная зависимость для тестов) -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>

    <!-- JUnit 5 Engine (для запуска тестов) -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!-- Maven Surefire Plugin (для запуска тестов при сборке) -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.2.2</version>
        </plugin>
    </plugins>
</build>

Теперь JUnit 5 автоматически найдет все классы с аннотацией @Test и выполнит проверки.

Для запуска тестов в командной строке терминала выполните команду:

mvn test

Если вы используете IDE (например, IntelliJ IDEA), тесты можно запускать прямо из интерфейса.

2. Лучшие практики Unit‑тестирования или как писать тесты, которым можно доверять

Лучшая практика № 1: Следуйте паттерну AAA (Arrange, Act, Assert)

  • Arrange (Подготовка): Создайте объекты и задайте начальные условия.

  • Act (Действие): Вызовите тестируемый метод.

  • Assert (Проверка): Убедитесь, что результат соответствует ожиданиям.

Пример:

@Test
void testAddition() {
    // Arrange
    Calculator calc = new Calculator();
    int a = 5, b = 3;
    
    // Act
    int result = calc.add(a, b);
    
    // Assert
    assertEquals(8, result, "5 + 3 должно быть 8");
}

Лучшая практика № 2: Тестируйте граничные случаи Проверяйте не только «хорошие» сценарии, но и крайние значения. Например:

  • Для метода divide() — деление на Integer.MAX_VALUE, отрицательные числа.

  • Для метода withdrawMoney() в банкомате — попытка снять больше, чем есть на счете.

Лучшая практика № 3: Тесты должны быть независимыми

  • Каждый тест должен работать изолированно. Не используйте общие переменные между тестами — это приводит к случайным ошибкам.

Лучшая практика № 4: Читаемые имена тестов. Имя теста должно чётко описывать, что он проверяет. Например:

  • testWithdrawMoney_InsufficientFunds() — понятно, что тест проверяет снятие денег при недостатке средств.

Лучшая практика №5: Проверяйте не только успешные сценарии, но и ошибки:

  • Используйте assertThrows(), чтобы убедиться, что метод корректно обрабатывает ошибки.

3. Какие еще есть инструменты тестирования?

Инструментов тестирования достаточно много. Наиболее часто встречается использование библиотеки Mockito, которая применяется для создания «заглушек» (mock‑объектов), если ваш код зависит от внешних сервисов.

Unit‑тестирование не должно зависеть от окружения, поэтому моки (mock‑объекты) играют ключевую роль: они заменяют реальные зависимости (базы данных, API, файловые системы) на управляемые заглушки. Это позволяет тестировать код изолированно, без подключения к внешним сервисам, что делает тесты стабильными, быстрыми и независимыми от внешних условий.

Вместо проверки работы с реальной БД вы можете смоделировать её ответы, чтобы проверить только логику вашего класса. Такой подход устраняет «шум» от сторонних систем и гарантирует, что тесты проверяют именно ваш код, а не его окружение.

Например если у вас в проекте есть класс, который использует внешний сервис:

public class UserService {
    private final Database database;
    
    public UserService(Database database) {
        this.database = database;
    }
    
    public boolean isUserValid(String username) {
        User user = database.findUser(username);
        return user != null && user.isActive();
    }
}

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

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

@Test
void testIsUserValid_UserNotFound() {
    // Arrange
    Database mockDatabase = Mockito.mock(Database.class);
    Mockito.when(mockDatabase.findUser("unknown")).thenReturn(null);
    UserService service = new UserService(mockDatabase);
    
    // Act & Assert
    assertFalse(service.isUserValid("unknown"));
}

В этом методе testIsUserValid_UserNotFound() мы мокаем базу данных — создаём «поддельный» объект Database, чтобы не зависеть от реального подключения. Задаём поведение — указываем, что при запросе несуществующего пользователя мок вернёт null. Проверяем логику — убеждаемся, что сервис корректно обрабатывает отсутствие пользователя (возвращает false). И тест проверяет обработку ошибок в сервисе, используя имитацию базы данных для изоляции кода от внешних зависимостей.

4. Почему тесты действительно экономят время?

Представьте, что вы исправляете баг в старом коде. Без тестов вы будете перепроверять всё вручную. С тестами — запустите их один раз, и они покажут, всё ли работает.

Кроме того у тестов есть и «психологический бонус». Тесты — это как страховочная сетка для разработчика. Когда код покрыт тестами, вы смелее берётесь за рефакторинг или добавление новых функций. Вы знаете: если что‑то сломается — тесты сразу «закричат». Это убирает страх ошибки и ускоряет разработку.

Представьте, что вы ремонтируете машину. Без диагностики после каждой операции вы будете каждый раз проверять двигатель, тормоза и электронику вручную. С тестами — подключили «автотестер», нажали кнопку, и он мгновенно покажет, всё ли в порядке. Вы экономите часы на проверках и работаете спокойнее.

Заключение или тестирование — это не обуза, а ваша суперсила!

Unit‑тесты помогают:

  • Ловить ошибки на ранних этапах.

  • Делать рефакторинг безопасно (изменения не сломают существующий код).

  • Документировать код через примеры (тесты показывают, как метод должен работать).

Совет: Начинайте писать тесты сразу, как только создали метод. Это проще, чем исправлять баги потом!


Если вы задумываетесь о масштабировании подхода к тестированию — рекомендуем посетить эти открытые уроки. Они помогут выйти за рамки базового JUnit и расширить практический инструментарий:

29 апреля, 20:00
Облако в кармане: запускаем всю инфраструктуру для теста при сборке
Как автоматизировать запуск зависимых компонентов (БД, микросервисов и др.) прямо из Gradle. Подходы, инструменты, сравнение вариантов.

30 апреля, 20:00
Альтернативные тест-раннеры. Использование stestr в API и юнит тестировании
Сравнение stestr и PyTest, написание автотестов на API и UI, плюсы и минусы подхода в реальных сценариях.

Все актуальные инструменты и методы тестирования можно освоить на онлайн-курсах OTUS под руководством экспертов-практиков.

Теги:
Хабы:
0
Комментарии0

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS