Заміна UI авторизації на API для автотестів
На мою думку, одним з найбільших викликів в автоматизованому тестуванні є забезпечити його надійність. У питанні покращення показників надійності гарно себе зарекомендував підхід використання API інтерфейсу замість UI.
У статті ми докладно розберемо механізм заміни UI авторизації на API. Існує багато видів аутентифікації — Basic, Digest, Form, OAuth 1 and OAuth 2. Для прикладу, я пропоную розглянути одну з найпростіших, а саме — Form. Основною метою статті є показати підхід при впровадженні API авторизації для UI тестів. Тести та імплементацію будемо писати на джаві. З іструментів будемо використовувати — Chrome DevTools.
В якості об’єктів тестування використаємо Kanboard та DVWA. Це open source продукти з відкритою ліцензією, які досить просто розгорнути локально. За посиланнями можна прочитати більше про ці продукти і ознайомитися з інструкціями їх розгортки.
Проект створюємо за допомогою maven та додаємо testng, selenide, rest-assured, json-path, jsoup, maven-compiler-plugin та maven-surefire-plugin. Проект можна переглянути за посиланням.
Логинимся в Kanboard в браузері Chrome з відкритою вкладкою Network Chrome DevTools.


Проаналізувавши DevTools, ми можемо дізнатися алгоритм авторизації. Для авторизації здійснюється два запити: GET з двома query параметрами та POST з парою логін/пароль та csrf токеном. Перший запит необхідний, щоб отримати KB_SID cookie. Другий — для KB_RM cookie. Встановивши обидва цих значення у WebDriver, ми отримаємо доступ до головної сторінки.
Перший запит у RestAssured буде виглядати наступним чином:
Response response01 = given()
.queryParam("controller", "AuthController")
.queryParam("action", "login")
.when()
.get(BASE_URL);
З нього ми отримуємо KB_SID cookie
String cookieKBSID = response01.getCookie("KB_SID");
CSRF токен знаходиться у домі HTML сторінки, яку ми можемо бачити в тілі респонсу.

Отримати його нам допоможе бібліотека jsoup, яка дозволяє розділяти документ на елементи. Пошук здійснюється схожим способом, як і Web елементи.
String cSRFToken = Jsoup.parseBodyFragment(response01.body().asString())
.getElementsByAttributeValue("name", "csrf_token").attr("value");
Другий запит у RestAssured буде виглядати наступним чином
Response response02 = RestAssured.given()
.config(RestAssured.config().encoderConfig(EncoderConfig.encoderConfig()
.encodeContentTypeAs("x-www-form-urlencoded", ContentType.URLENC)))
.contentType("application/x-www-form-urlencoded; charset=UTF-8")
.formParam("remember_me", "1")
.formParam("username", "admin")
.formParam("password", "admin")
.formParam("csrf_token", cSRFToken)
.queryParam("controller", "AuthController")
.queryParam("action", "check")
.cookie("KB_SID", cookieKBSID)
.when()
.post(BASE_URL);
Тут варто зауважити, що запит необхідно правильно заенкодити (encoderConfig, encodeContentTypeAs). З нього ми отримуємо KB_RM cookie.
String setCookieHeaderValue = response02.header("Set-Cookie");
Тепер, коли ми отримали всі необхідні елементи, нам залишається тільки відкрити потрібну сторінку з заповненими полями cookie.
WebDriverRunner.getWebDriver()
.manage().addCookie(new Cookie("KB_SID", cookieKBSID));
WebDriverRunner.getWebDriver()
.manage().addCookie(new Cookie("KB_RM", cookieKBRM));
Selenide.open(url);
Для DVWA все відбувається майже так само, тільки токен матиме іншу назву, детальніше можна переглянути на gitlab. Зрозуміло, що для інших видів аутентифікації, кількість запитів і їх складність буде більшою. Проте базовий принцип залишається незмінним — проаналізувати алгоритм і відтворити за допомогою RestAssured.
Дякую за увагу і сподіваюся, що ця стаття була корисною для Вас.
8 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівНеплохо
Так же, как и без этого ) Зачем логиниться в каждом тесте? Достаточно 1 теста на логин, а в остальных логиниться через апишку для экономии времени. Так же и дальше — можно перейти сразу на вторую страницу по урле. Главное при этом не забыть оставить хотя бы по одному тесту, который проверит навигацию. Ещё большой плюс такого подхода — если ломался переход со страницы 1 на страницу 2, то упадёт 1 полный тест, который проходится по этим переходам, а остальные тесты на странице 2 будут работать.
Покращення — воно таке. Пиши вже assert(true), головне ж показники
Главное — спокойный сон команды. Если тесты ранятся 6 часов и часто половина падает, то сна не будет. Если такой подход оставляет прежнее покрытие, но при этом снижает время ранов и количество упавших тестов, то при чём здесь assert(true) ?
Так здесь же и собака порылась. Берётся на веру, то бишь assert (true), что такой подход оставляет прежнее покрытие.
Разумеется, API для тестов это хорошо. Ровно до тех пор, пока кто-то не очень доброжелательный это API нащупает и DDOS по нему проведёт. Не то чтоб проблема нерешаема, просто её решение требует время-денег, и обычно оказывается что на безопасность там положено с прибором.
Я думал уже все давно так делают)
Я теж колись думав що спеціалісти від Skype вже відмовились, jQuery тільки в закинутих проектах, а в аутсорсі все покривають тестами