HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Сложно переоценить важность паттернов. Они помогают писать код более структурировано, тратить меньше времени на отладку кода, позволяют новым людям в команде быстрее и проще влиться в процесс.</p>
1 <p>Сложно переоценить важность паттернов. Они помогают писать код более структурировано, тратить меньше времени на отладку кода, позволяют новым людям в команде быстрее и проще влиться в процесс.</p>
2 <p>Как в разработке, так и в тестировании есть свои паттерны. И, безусловно, самым популярным и востребованным паттерном разработки автотестов является паттерн Page Object.</p>
2 <p>Как в разработке, так и в тестировании есть свои паттерны. И, безусловно, самым популярным и востребованным паттерном разработки автотестов является паттерн Page Object.</p>
3 <p><strong>Page Object</strong>(далее PO) - паттерн проектирования автотестов, когда логика (методы, функции) отделены от самих тестов.</p>
3 <p><strong>Page Object</strong>(далее PO) - паттерн проектирования автотестов, когда логика (методы, функции) отделены от самих тестов.</p>
4 <p>Данный паттерн позволяет более эффективно писать код, вызывая в тесте нужные нам методы:</p>
4 <p>Данный паттерн позволяет более эффективно писать код, вызывая в тесте нужные нам методы:</p>
5 productPage .clickDeliveryBtn() .clickCheckoutBtn();<p>Этот паттерн хорошо себя показывает ровно до момента, пока вы не попадаете на проект, где реализована технология<strong>SPA</strong>(Single Page Application).</p>
5 productPage .clickDeliveryBtn() .clickCheckoutBtn();<p>Этот паттерн хорошо себя показывает ровно до момента, пока вы не попадаете на проект, где реализована технология<strong>SPA</strong>(Single Page Application).</p>
6 <p>Представим себе типичный интернет-магазин. На каждой странице есть подвал (далее footer) и шапка (далее header). В Header'е и в footer'е есть поле ввода текста (поиск).</p>
6 <p>Представим себе типичный интернет-магазин. На каждой странице есть подвал (далее footer) и шапка (далее header). В Header'е и в footer'е есть поле ввода текста (поиск).</p>
7 <p>Как нам в данном случае поступить? Использовать классический PO, описывая на каждой странице и footer, и header? Это будет нарушением принципа DRY (Don't Repeat Yourself), к тому же, при изменении одного из элементов (к примеру, в header был добавлен новый элемент) придется ходить по всем страницам и изменять в каждом классе.</p>
7 <p>Как нам в данном случае поступить? Использовать классический PO, описывая на каждой странице и footer, и header? Это будет нарушением принципа DRY (Don't Repeat Yourself), к тому же, при изменении одного из элементов (к примеру, в header был добавлен новый элемент) придется ходить по всем страницам и изменять в каждом классе.</p>
8 <p>Использовать некий, промежуточный класс? Тогда в некоторых классах, описывающих страницы, будут "лишние" методы. К примеру, на подробном описании страницы есть только footer, в корзине есть только header. Если у нас будет один общий класс, где описан header и footer, то на страницах подробного описания у нас будут методы для footer'a, что будет мешать в разработке (и может привести к некорректному поведению тестов).</p>
8 <p>Использовать некий, промежуточный класс? Тогда в некоторых классах, описывающих страницы, будут "лишние" методы. К примеру, на подробном описании страницы есть только footer, в корзине есть только header. Если у нас будет один общий класс, где описан header и footer, то на страницах подробного описания у нас будут методы для footer'a, что будет мешать в разработке (и может привести к некорректному поведению тестов).</p>
9 <p>Сделать несколько классов, где будут вариации наследования? Опять же, нарушение принципов DRY(а так же SOLID), а сколько будет вариаций при, скажем, 4 вариантов header'a и footer'a страшно представить.</p>
9 <p>Сделать несколько классов, где будут вариации наследования? Опять же, нарушение принципов DRY(а так же SOLID), а сколько будет вариаций при, скажем, 4 вариантов header'a и footer'a страшно представить.</p>
10 <p>На помощь нам приходит дальнейшая эволюция PO в виде<strong>WO (Widget Object), ScreenPlay</strong>, но, по моему мнению, они не удобны.</p>
10 <p>На помощь нам приходит дальнейшая эволюция PO в виде<strong>WO (Widget Object), ScreenPlay</strong>, но, по моему мнению, они не удобны.</p>
11 <p>WO не удобен с точки зрения восприятия (если использовать "чистый" WO). Вот у нас не отработал виджет поиска. На какой странице это случилось? Как понять?</p>
11 <p>WO не удобен с точки зрения восприятия (если использовать "чистый" WO). Вот у нас не отработал виджет поиска. На какой странице это случилось? Как понять?</p>
12 <p>Использовать смешанное решение в виде PO + WO? Встает снова вопрос с наследованием. Как нам наследоваться от нескольких виджетов? Создать на каждой странице/тесте n виджетов? Опять же, нарушение DRY со всеми вытекающими.</p>
12 <p>Использовать смешанное решение в виде PO + WO? Встает снова вопрос с наследованием. Как нам наследоваться от нескольких виджетов? Создать на каждой странице/тесте n виджетов? Опять же, нарушение DRY со всеми вытекающими.</p>
13 <p>Использовать паттерн<strong>ScreenPlay</strong>? Не все используют<strong>Cucumber/Serenity</strong>.</p>
13 <p>Использовать паттерн<strong>ScreenPlay</strong>? Не все используют<strong>Cucumber/Serenity</strong>.</p>
14 <h2>Паттерн Traits</h2>
14 <h2>Паттерн Traits</h2>
15 <p>Начиная с Java 8, в интерфейсах ради сохранения обратной совместимости был добавлен модификатор<strong>default</strong>. Данный модификатор позволяет в интерфейсе<strong>реализовать</strong>метод по умолчанию. Это и позволит нам реализовать паттерн Traits, ведь множественное наследование интерфейсов в Java не запрещено.</p>
15 <p>Начиная с Java 8, в интерфейсах ради сохранения обратной совместимости был добавлен модификатор<strong>default</strong>. Данный модификатор позволяет в интерфейсе<strong>реализовать</strong>метод по умолчанию. Это и позволит нам реализовать паттерн Traits, ведь множественное наследование интерфейсов в Java не запрещено.</p>
16 <p>Паттерн Traits используется в объектно-ориентированном программировании, который представляет собой набор методов, которые могут быть использованы, чтобы расширить функциональные возможности класса.</p>
16 <p>Паттерн Traits используется в объектно-ориентированном программировании, который представляет собой набор методов, которые могут быть использованы, чтобы расширить функциональные возможности класса.</p>
17 <p>Или, простыми словами, для каждого теста мы "собираем" свои методы, которые нам нужны для конкретного теста. Нам нужен header? Подключаем интерфейс с методами для header'a. Нам еще нужны методы для главной страницы? Нет ничего проще, подключаем интерфейс MainPage.</p>
17 <p>Или, простыми словами, для каждого теста мы "собираем" свои методы, которые нам нужны для конкретного теста. Нам нужен header? Подключаем интерфейс с методами для header'a. Нам еще нужны методы для главной страницы? Нет ничего проще, подключаем интерфейс MainPage.</p>
18 <p>Простой пример использования данного паттерна. Создадим простейший интерфейс, который будет выводить нам текст "Here you trait!"</p>
18 <p>Простой пример использования данного паттерна. Создадим простейший интерфейс, который будет выводить нам текст "Here you trait!"</p>
19 public interface Trait { default Trait giveMeTrait(){ System.out.println("Here you trait!"); return this; } }<p>И имплементируем его в наш класс:</p>
19 public interface Trait { default Trait giveMeTrait(){ System.out.println("Here you trait!"); return this; } }<p>И имплементируем его в наш класс:</p>
20 public class MyTraitClass implements Trait{ @Test void testTrait(){ giveMeTrait(); } }<p>Готово. Таким образом мы можем подключить только нужные trait в тест, избавившись от ненужных в данном тесте методов.</p>
20 public class MyTraitClass implements Trait{ @Test void testTrait(){ giveMeTrait(); } }<p>Готово. Таким образом мы можем подключить только нужные trait в тест, избавившись от ненужных в данном тесте методов.</p>
21  
21