Flaky tests
Метод
Андрей Солнцев
twitter.com/asolntsev
asolntsev.github.io/ru/video/
В предыдущих сериях
“Flaky tests”
SeleniumCamp 2018
“Flaky tests 2.0”
DelEx 2019
https://asolntsev.github.io/ru/video/
В предыдущих сериях
“Flaky tests”
SeleniumCamp 2018
“Flaky tests 2.0”
DelEx 2019
Сегодня:
Flaky test
- это тест, который падает иногда
Ой, 30 тестов упало.�Надо изучить!
… Впрочем, �П……У….. !
Ой, 30 тестов упало.�Надо изучить!
… Впрочем, Перезапущу!
Каждый билд нужно изучать вручную
И вы называете это автоматизацией?
Индустрия в опасности!
Порядок
Как вы это протестируете?
Тест:
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.ok”).click();
$(“.saving”).should(disappear)
Тест:
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.ok”).click();
$(“.saving”).should(disappear)
selenide.org
Усложняем задачу
Тест:
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.saving”).should(disappear)
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.saving”).should(disappear)
Что может пойти не так?
Вариант 1: шустрый браузер
$(“.save”).click();
$(“.saving”).should(appear);
$(“.saving”).should(disappear)
FAILED
Вариант 2: тормознутый браузер
1) “Сохранить”
$(“.save”).click();
$(“.saving”).should(appear);
$(“.saving”).should(disappear)
2) “Сохраняю…”
> 4 сек
3) Пропадает
FAILED
Компромисс 1
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.saving”).should(disappear)
FAILED
Идём на компромисс.
Отказываемся от этой проверки.
Компромисс 2
$(“.save”).click();�
$(“.saving”).should(appear);�
$(“.saving”).should(disappear)
НЕ НАХОДИТ БАГУ
Идём на компромисс.
Отказываемся от этой проверки.
Итак,�как надёжно проверить
кейс
“Сохранить”?
Как надёжно проверить�кейс “Сохранить”?
Правильный ответ:
НИКАК!
(без хитрых хаков)
Почувствуй разницу:
Мы контролируем
Мы НЕ контролируем
Почувствуй разницу:
Тест надёжный
Тест ненадёжный
Порядок в тесте:
Порядок в тестах
Этот принцип - на каждом шагу!
Пример:
Автосохранение
видео
Логи AUT и теста:
10:59:12,865 UITest click.before <a>1 Contact and Addresses</a>
10:59:13,121 UITest click.before <button>Start filling</button>
10:59:13,686 UITest click.before <button>Forward</button>
10:59:13,851 UITest click.before <a>5 Preview</a>
10:59:13,905 request POST /loanapplications/mortgage/save ...
10:59:14,010 UITest click.after <a>5 Preview</a>
Когда тест зелёный:
Когда тест красный:
click.before <a>1 Contact and Addresses</a>
click.before <button>Start filling</button>
click.before <button>Forward</button>
click.before <a>5 Preview</a>
POST /loanapplications/mortgage/save ...
click.after <a>5 Preview</a>
click.before <a>5 Preview</a>
click.after <a>5 Preview</a>
POST /loanapplications/mortgage/save ...
Хорошая идея -
совместить логи
теста и приложения
Но как же решить�нашу задачу�с автосохранением?
Как-то контролировать порядок!
Но как?
Как дождаться автосохранения?
Нет.
Всё это мы не контролируем.
В AUT: добавляем признак
function autosaveDraft() {
self.form.removeClass('autosaved');
self.form.addClass('autosaving');
$.post(...)� .then(() => {
self.form.addClass('autosaved');� })
В тесте: проверяем признак
// заполняем форму, кликаем “Дальше”
$("#form").shouldHave(cssClass("autosaving"));
$("#form").shouldHave(cssClass("autosaved"));
А вдруг он остался от �предыдущего автосохранения?
В тесте: проверяем признак
// Arrange:
executeJavaScript("document.getElementById('form').classList.remove('autosaving')");
// Act: заполняем форму, кликаем “Дальше”
$("#form").shouldHave(cssClass("autosaving"));
$("#form").shouldHave(cssClass("autosaved"));
Unit-test
UI test
AAA - �на каждом шаге!
Шаг 1
Шаг 2
https://seleniumcamp.com/talk/arrange-mazafaka/
Arrange!
Перед каждым шагом:
Хочешь поймать �флейки тест �-
думай как флейки тест!
Пример:
Три-четыре
видео
Есть flaky тест
$$("#devices .device").shouldHave(size(4));
Изредка тест ломается:
List size mismatch: expected: = 4, actual: 3
Elements: [
<tr class="device">BlackBerry</tr>,
<tr class="device">Lumia</tr>,
<tr class="device">HTC</tr>
]
Смотрим тест вдумчиво:
$(".remove-device").click();
$$("#devices .device").shouldHave(size(4));
$$("#devices .device").shouldHave(
texts("BlackBerry", "Lumia", "HTC")
);
Смотрим тест вдумчиво:
$(".remove-device").click();
$$("#devices .device").shouldHave(size(4));
$$("#devices .device").shouldHave(
texts("BlackBerry", "Lumia", "HTC")
);
Почему строк 4, но текста 3?
Исправленный тест:
$$("#devices .device").shouldHave(size(4));
$(".remove-device").click();
$$("#devices .device").shouldHave(size(3));
$$("#devices .device").shouldHave(
texts("BlackBerry", "Lumia", "HTC")
);
Пример:
Ожидается -1 строк
Правильный тест (вроде бы?)
@Test
public void closeDeposit() {
fastLogin("/deposits");
int openDeposits = $$("#deposits tbody tr").size();
// bla-bla-bla закрыть депозит
$$("#deposits tbody tr").shouldHave(size(openDeposits - 1));
}
Правильный тест (вроде бы?)
@Test
public void closeDeposit() {
fastLogin("/deposits");
int openDeposits = $$("#deposits tbody tr").size();
// bla-bla-bla закрыть депозит
$$("#deposits tbody tr").shouldHave(
size(openDeposits - 1)
);
}
ARRANGE
ACT
ASSERT
Но иногда он падает:
List size mismatch: expected: = -1, actual: 3, collection: #deposits tbody tr
Elements: [
<tr>73456 810 0 3331 0007779 Topupable 1 year 2.35% 25.04.2020 Active</tr>,
<tr>Deferred Deferred 6 months 3.67% 01.07.2017 Deferred</tr>,
<tr>Deferred Deferred 6 months 3.67% 01.07.2017 Deferred</tr>
]
Их и правда 3:
Но тогда что это за хрень?
Это халтура, а не ARRANGE!
@Test
public void closeDeposit() {
fastLogin("/deposits");
int openDeposits = $$("#deposits tbody tr").size();
// bla-bla-bla закрыть депозит
$$("#deposits tbody tr").shouldHave(
size(openDeposits - 1)
);
}
ARRANGE
Список ещё не успел подгрузиться
Когда тестируешь UI�-
ты не можешь �доверять UI
Вот правильный ARRANGE:
@Test
public void closeDeposit() {
fastLogin("/deposits");
// bla-bla-bla закрыть депозит
$$("#deposits tbody tr").shouldHave(
size(openDeposits - 1)
);
}
ARRANGE
int openDeposits = DB.select(“count(*) from deposits”);
$$("#deposits tbody tr").shouldHave(size(openDeposits));
size(openDeposits - 1)
Вот правильный ARRANGE:
@Test
public void closeDeposit() {
fastLogin("/deposits");
int openDeposits = DB.select(“count(*) from deposits”);
$$("#deposits tbody tr").shouldHave(size(openDeposits));
Пример:
Сотри за мной нежно
Тест ок
Тест failed
Кнопка есть. Ок.
Кнопки нет, потому что �эта штука уже активирована
Версия
Осталось �от предыдущего теста?
Как подчищаются данные:
@After
public void deleteRegistration() {
if ($("#turnoff").is(visible)) {
$("#turnoff").click();
}
}
Предыдущий тест:
| ...
|.alert-success |should have(text 'done successfully') |PASS |
|#sbp-turnoff-confirmation-button |is(visible) |PASS |
|#sbp-turnoff-confirmation-button |click() |PASS |
|#sbp-turnoff-button |click() |PASS |
+---------------------------------+----------------------+----------+----------|
| ...
|.alert-success |should have(text 'done successfully') |PASS |
|#sbp-turnoff-confirmation-button |is(visible) |PASS |
+---------------------------------+----------------------+----------+----------|
А когда наш тест упал:
Неправильно:
Правильно:
@After
public void delete() {
...
}
@Before
public void delete() {
...
}
Неправильно:
Правильно:
@After
public void delete() {
if ($(...)
.is(visible)) {
...
}
}
@Before
public void delete() {
DB.executeSQL(
“delete from orders”
);
}
И наконец,
Метод (изучения флейки теста)
Море гипотез
Метод (изучения флейки теста)
Море гипотез
Гипотеза 1
делим море пополам
Метод (изучения флейки теста)
Море гипотез
Метод (изучения флейки теста)
Море гипотез
Гипотеза 2
Гипотеза 3
Гипотеза 4
и т.д.
Метод (изучения флейки теста)
Пример
org.openqa.selenium.TimeoutException:
timeout: Timed out receiving message from renderer: 10.000
Проверяем гипотезу
Гипотеза:
размер (картинок)�имеет значение
Проверяем гипотезу
Похоже, правда!
Вылечил флейки тест
Значит,
Он упадёт завтра!
Следить за тестами -�Это как печь зефир
Следить за тестами -�Это как печь зефир
Нужно следить постоянно,�Иначе может подгореть
Следить за тестами -�Это как печь зефир
Нужно следить постоянно,�Иначе может подгореть
Нужно много времени�И терпения
Следить за тестами -�Это как печь зефир
Нужно следить постоянно,�Иначе может подгореть
Нужно много времени�И терпения
Фигачьте�вдумчиво
Андрей Солнцев
@asolntsev
asolntsev.github.io
ru.selenide.org