Новые функции Java для автоматизаторов

Java развивается, вводятся новые возможности, значительно улучшающие подходы в автоматизации QA. Позвольте мне рассказать об относительно свежих значимых дополнениях в Java, которые можно использовать в своих automation-проектах.

Шаблоны строк (Java 21 Preview, Java 24)

Шаблоны строк (String Templates) в Java 21 и 24 представляют собой значительное улучшение операций с динамическими строками.

В Java традиционно используется конкатенация строк — или String.format() для создания строк с изменяемым содержимым. У обоих подходов есть недостатки.

  • Конкатенация становится беспорядочной при большом количестве переменных.
  • String.format() требует сопоставления спецификаторов формата (%s, %d) с переменными в правильном порядке.
  • Оба способа чреваты ошибками и трудночитаемы в сложных строках.

Шаблоны строк позволяют вставлять выражения непосредственно в строки в понятном и читаемом виде.

// Использование функции String Template
// Префикс STR. перед строкой (это процессор шаблонов)
// Использование фигурных скобок \{выражение} для вставки значений
// Возможность поместить любое допустимое выражение Java внутрь скобок

String name = "Test";
int age = 25;
String message = STR."Hello, my name is \{name} and I am \{age} years old.";
@Test
void testUserRegistration() {
    // Тестовые данные
    String username = "testUser123";
    String email = "test@example.com";
    String password = "SecureP@ss";
    
    // Использование шаблона строки для создания JSON-данных
    String requestBody = STR."""
    {
      "username": "\{username}",
      "email": "\{email}",
      "password": "\{password}",
      "createDate": "\{LocalDate.now()}"
    }
    """;
    
    // Используйте это тело запроса в своем тесте
    Response response = apiClient.post("/users", requestBody);
    
    // Ассерты
    assertEquals(201, response.getStatusCode());
}

Согласование шаблонов (Pattern Matching) (Java 16+)

Согласование шаблонов для instanceof изменило практику проверки типов и их приведение (casting) в тестовом коде. Эта функция сокращает количество шаблонов в тестовых ассертах и делает валидацию условий более читабельной.

// Старый подход
if (testResult instanceof SuccessResult) {
    SuccessResult success = (SuccessResult) testResult;
    verifySuccessData(success.getData());
}

// Новый подход с согласованием
if (testResult instanceof SuccessResult success) {
    verifySuccessData(success.getData());
}

Записи (Records) (Java 16+)

Records отлично подходят для создания простых, неизменяемых носителей данных (data carriers) в тестовом коде. Записи избавляют от необходимости писать конструкторы, геттеры, методы equals(), hashCode() и toString() для объектов тестовых данных.

// // Лаконично определяем структуры тестовых данных
record TestUser(String username, String email, boolean isActive) {}
record ExpectedResponse(int statusCode, String body, Map<String, String> headers) {}

@Test
void verifyUserRegistration() {
    TestUser user = new TestUser("testUser", "test@example.com", true);
    ExpectedResponse expected = new ExpectedResponse(200, "Success", Map.of("Content-Type", "application/json"));
    
    // Используем эти неизменяемые объекты в тестах
    ResponseEntity response = userService.register(user);
    assertEquals(expected.statusCode(), response.getStatusCode().value());
}

Текстовые блоки (Java 15+)

Текстовые блоки (Text Blocks) упрощают работу с многострочными строками, что полезно для тестовых данных в JSON/XML и SQL-запросах.

String jsonTestData = """
    {
      "username": "testUser",
      "password": "securePass123",
      "roles": ["user", "admin"],
      "settings": {
        "notifications": true,
        "theme": "dark"
      }
    }
    """;

Stream.toList() (Java 16+)

Небольшое, но значительное улучшение, упрощающее сбор результатов потока.

// Старый подход
List<String> errorMessages = testResults.stream()
    .filter(result -> !result.isPassed())
    .map(TestResult::getMessage)
    .collect(Collectors.toList());

// Новый подход
List<String> errorMessages = testResults.stream()
    .filter(result -> !result.isPassed())
    .map(TestResult::getMessage)
    .toList();

Stream.mapMulti() (Java 16+)

Пригодится для упрощения сложных тестовых структур данных.

List<TestScenario> flattenedTestCases = testSuites.stream()
    .mapMulti((suite, consumer) -> {
        suite.getTestCases().forEach(consumer);
    })
    .toList();

Исключения NullPointerExceptions (Java 14+)

Эта функция предоставляет точную информацию о том, какая именно переменная была null в цепочке.

// При неудаче с NPE в сообщении об исключении будет указано, какая именно часть была null.
user.getAddress().getCity().equals("New York");

// Вы можете сразу увидеть, что getCity() вернула null, что указывает непосредственно на источник проблемы.
java.lang.NullPointerException: Cannot invoke "com.example.City.equals(Object)" because the return value of "com.example.Address.getCity()" is null
    at com.example.YourClass.yourMethod(YourClass.java:42)

Улучшения Switch-выражений (Java 14+)

Выражения-переключатели (Switch expressions) делают логику тестов более лаконичной.

TestResult evaluateResponse(HttpStatus status) {
    return switch(status) {
        case OK, CREATED, ACCEPTED -> new TestResult(true, "Success");
        case NOT_FOUND -> new TestResult(false, "Resource not found");
        case UNAUTHORIZED, FORBIDDEN -> new TestResult(false, "Authentication error");
        default -> new TestResult(false, "Unexpected status: " + status);
    };
}

Улучшения класса String

В класс String было добавлено несколько полезных методов.

// isBlank() - Java 11
assertTrue(response.getBody().isBlank());

// методы strip() - Java 11
assertEquals("expected", response.getHeader("X-Value").strip());

// transform() - Java 12
List<String> logLines = testOutput.lines().toList();

// transform() - Java 12
String normalizedOutput = rawTestOutput.transform(String::toLowerCase)
                                      .transform(s -> s.replaceAll("\\s+", " "));

// formatted() - Java 15 (замена для String.format)
String testMessage = "Expected %s but got %s".formatted(expected, actual);

// indent() - Java 12
String prettyJson = rawJson.indent(2);

Улучшенная генерация случайных чисел (Java 17+)

Генераторы псевдослучайных чисел были усовершенствованы, что полезно для генерации случайных тестовых данных.

// Создаем новый генератор случайных чисел
RandomGenerator generator = RandomGenerator.of("L64X128MixRandom");

// Генерируем случайные тестовые данные
int randomAge = generator.nextInt(18, 99);
double randomSalary = generator.nextDouble(30000, 150000);

Убедитесь, что ваш проект настроен на использование новой версии Java (для большинства описанных выше функций рекомендуется Java 17+).

Medium

Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

? Популярное

? Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас