Как стать автором
Обновить

Domain Object with Lombok: Боевая классика

Время на прочтение4 мин
Количество просмотров3.6K
Domain Object (рус. «Доменный объект») — один из наиболее популярных подходов к использованию тестовых данных непосредственно в логике скриптов. На данный момент является одним из самых популярных и распространенных approach'ей, благодаря своей простоте, понятности и логичности.

Применим во всех видах автоматизации функционального тестирования (End-to-End, API, Integration), в независимости от проверяемой платформы, будь то Web, Mobile, или Desktop.
ВАЖНО: не стоит путать Domain Object с Data Transfer Object (DTO). Это абсолютно разные подходы, которые применяются в разных сферах.
В чем его суть?

Из другого названия подхода — «Business Object» — становится понятно, что это некая абстракция, представляющая собой модель и описание объекта, который важен именно для понимания и функционирования бизнес-логики приложения. Он не способен выполнять никаких функций, кроме «переноса» полей и их значений одного конкретного business-unit'а.
image



Как это выглядит


В качестве примера, возьмем любое приложение, где предусмотрено создание аккаунта пользователя. Именно пользователь и становится нашим доменным объектом. Практически во всех случаях, у юзера должны быть логин и пароль:

// Создаем доменный класс User
public class User {
// Объявляем, что User может содержать значение Login
  private String login;
// Объявляем, что User может содержать значение Password
  private String password;
}

Особенно внимательные заметят, что все внутренние поля являются private. Задавать и считывать значения напрямую из полей объекта считается плохой практикой. Вместо этого принято использовать всем хорошо известные геттеры и сеттеры:

public class User {

  private String login;

  private String password;

// Интерфейс для присваивания значения полю login
  public void setLogin(String login) {
    this.login = login;
  }

// Метод для получения значения login
  public String getLogin() {
    return this.login;
  }

// Аналогично для пароля
  public void setPassword(String password) {
    this.password = password;
  }

  public String getPassword() {
    return this.password;
  }
}

Теперь, мы получили доступ к полям, и можем задавать и считывать их значения. Но в данном примере у нас используется только два поля. А что произойдет, если этих полей будет пятнадцать? Верно, класс User разрастется до невиданных размеров, благодаря бесконечной копипасте getter'ов и setter'ов. Как же мы будем с этим справляться?



Магия Lombok


Здесь нам на помощь приходит Project Lombok — популярная библиотека, которая позволяет сократить код в несколько раз, избежать copy/paste-страданий, и значительно уменьшить количество времени на написание Data Object-классов. Несколько полезных ссылок:


Что же он делает? Автоматически создает геттеры и сеттеры для всех полей класса, путем присваивания ему соответствующей аннотации:

import lombok.Getter;
import lombok.Setter;

// Объявляем геттеры для всех полей класса User
@Getter
// Объявляем сеттеры для всех полей класса User
@Setter
public class User {

  private String login;

  private String password;
}

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



Применяем в тесте


Хороший тест — это тест, в котором четко разделены тестовые данные, тестовая логика, и ее реализация.

Попробуем залогинить нашего пользователя. Создаем класс с тестовыми данными, и «наполняем» ими нового User'а:

// Создаем Test Data класс
public class TestDataUser {

// Объявляем private-константы с тестовыми данными
  private final static String DEFAULT_LOGIN = "vasiliy_pupkin";
  private final static String DEFAULT_PASSWORD = "q1w2e3";

// Реализуем статический метод для получения дефолтного юзера
  public static User getDefaultUser() {
// Создаем "чистого" пользователя
    User user = new User();
// Используем сеттер для присваивания значения Login
    user.setLogin(DEFAULT_LOGIN);
// Используем сеттер для присваивания значения Password
    user.setPassword(DEFAULT_PASSWORD);
// Возвращаем объект класса User, наполненного нужными нам данными
    return user;
  }
}

Описываем модель Login-страницы:

public class LoginPage {

// Создаем public-метод логина, который принимает объект User
  public void loginUser(User user) {
// Через геттер получаем логин и передаем его в метод enterLogin()
    enterLogin(user.getLogin());
// Аналогично с паролем
    enterPassword(user.getPassword());
  }

  private void enterLogin(String login) {
    this.loginInput.sendKeys(login);
  }

  private void enterPassword(String password) {
    this.passwordInput.sendKeys(password);
  }
}

Осталось только реализовать тестовый класс:

public class LoginTest {

  @Test
  public void loginAsDefaultUser() {
// Получаем объект с credentials тестового юзера
    User user = TestDataUser.getDefaultUser();
// Инициализируем Login-страницу
    LoginPage loginPage = new LoginPage();
// Логинимся, используя ранее полученный объект
    loginPage.loginUser(user);
  }
}

Готово! Вы великолепны!


Подведем итоги


В финале мы получаем аккуратную архитектуру проекта, с четким разделением логики, данных, и реализации. Lombok помогает избавиться от дублирования кода, Domain Object замечательно вписывается в философию Page Object, а поддержка кода становится сплошным удовольствием.

Должны же быть минусы?

  1. Иммутабельность. А точнее, ее отсутствие. В этом данный подход с использованием Lombok проигрывает основном конкуренту — Builder (статья на Хабре). Зато, на мой взгляд, приведенный выше код является более «чистым», понятным, и эстетически приятным, по сравнению с нескончаемой цепочкой в билдере и нагромождением методов в Object-классе.
  2. Увеличение complexity там, где это не нужно. Не столько минус, сколько небольшое напоминание. Любой подход или паттерн имеет проблематику и должен решать некую проблему. Не стоит пытаться использовать Data Object в юнит-тесте, который всего лишь проверяет, что 2+2=4.

Большое спасибо за внимание. Буду рад отзывам и критике.

P.S. Расскажите в комментариях, какие подходы вы используете в работе. Будет очень интересно почитать.
Теги:
Хабы:
Всего голосов 12: ↑6 и ↓60
Комментарии5

Публикации

Истории

Работа

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
14 сентября
Конференция Practical ML Conf
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн