UI інтеграційні тести для React аплікації на Java
Привіт мене звати Олександр і час від часу я пишу статті про автоматизоване тестування на джаві. Працюю на посаді Lead Software Test Automation Engineer.
Однією з найбільших проблем автоматизованого тестування є надійність тестів, а саме кількість false positive результатів. Однією з умов надійних тестів є їх ізоляція. Логічним продовженням ідеї ізоляції є перехід на сходинку нижче у тестовій піраміді і використання інтеграційних тестів.
Такі тести мають ряд переваг таких як надійність та швидкість виконання. Проте мають і декілька недоліків, головними з яких є значна складність підтримки mocked даних (дані, які будуть використані аплікацією замість даних від сторонніх сервісів), а також неможливість виявити деякі дефекти.
В мережі є багато матеріалів по E2E-тестуванню і значно менше про інтеграційне тестування. Через це, на мою думку, стаття буде цікавою широкій аудиторії. У ній продемостровано підхід до побудови інтеграційних тестів для простої React аплікації, яка відображає цікавий факт про котів. Сам факт отримується зі стороннього сервісу.
Тест з котом
import { useEffect, useState } from "react"; function App() { const [fact, setFact] = useState(""); useEffect(() => { fetch(process.env.REACT_APP_CAT_FACT_URL) .then((response) => response.json()) .then((data) => setFact(data.fact)) .catch((error) => console.log(error)); }, []); return ( <div className="App"> <h1>Cat Fact</h1> <p data-test-id="fact-text">{fact}</p> </div> ); } export default App;
Ця аплікація має два режими роботи, а саме робота з реальним сервісом (https://catfact.ninja/fact) та робота з mock-сервісом (http://localhost:8080/fact).
В тесті я планую перевірити, що користувач має можливість бачити факт про кота. І з цим є дві проблеми. По-перше, аплікація залежна від стороннього сервісу, який нам би не хотілось тестувати, бо ми ним не володіємо.
По-друге, через те, що факт генерується випадковим чином, наш тест стає або занадто абстрактним і ми не перевіряємо конкретний факт, або нестабільним, тому що факт кожен раз змінюється. Обидві ці проблеми вирішуються за допомогою підставляння наших даних замість реальних даних від сервісу.
Фреймворк
Тестовий фреймворк складається з Maven, Lombok, TestNG, Wirework, Cucumber та Selenide. Також використана класична layered-архітектура.
Тестовий фреймворк зберігається у тому самому репозиторії, що і аплікація. Це зроблено для синхронізації версій тестів та аплікації.
@integration Feature: Data presentation Scenario Outline: User is able to see cat fact When [Sys] Cat fact service is mocked When [UI] User opens main page Then [UI] The cat fact <catFact> should be shown Examples: Examples: | catFact | | Approximately 40,000 people are bitten by cats in the U.S. annually. |
Єдина відміність від E2E-тестів в додатковому кроці, в якому прописується, як mock-сервіс має відповідати на запит аплікації.
@When("[Sys] Cat fact service is mocked") public void catFactServiceIsMocked() throws IOException { String json = new String(Files.readAllBytes(Paths.get(mockJsonLocation() + "/catFact.json"))); stubFor(get(urlEqualTo("/fact")) .willReturn(aResponse() .withStatus(200) .withHeader("Access-Control-Allow-Origin", "*") .withBody(json))); }
Для розгортання аплікації можна використати наступні команди:
npm run start:development // external service is mocked npm run start:production // external service is NOT mocked
Для локального тестування та для розробки тестів можна використати Mockoon, як mock-сервер.
При виконанні інтеграційних тестів Mockoon не потрібен, тому що Wiremock сервер підіймається в методі beforeAll.
public class MockHooks { private final static WireMockServer wireMockServer = new WireMockServer(); @BeforeAll public static void startWiremockServer() { wireMockServer.start(); } @AfterAll public static void stopWiremockServer() { wireMockServer.stop(); } }
Jenkins pipeline складається з чотирьох кроків, а саме:
- клонування репозиторію;
- розгортання аплікації у dev моді;
- виконання інтеграційний тестів;
- генерація репорту.
pipeline { agent any stages { stage('Clone repo') { steps { git credentialsId: 'git', branch: 'main', url: 'https://gitlab.com/OleksandrPodoliako/cat-fact.git' } } stage('Build and start app') { steps { dir('app') { bat 'npm install' bat 'start /B cmd /C "npm run start:development | findstr /C:\"Compiled successfully!\""' } } } stage('Run integration tests') { steps { dir('integration-tests') { bat 'mvn clean test -Pui-integration' } } } stage('Generate report') { steps { dir('integration-tests') { publishHTML([allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'target/cucumber-reports', reportFiles: 'cucumber-report.html', reportName: 'Cucumber Report']) } } } } }
Повний код фреймворку можна знайти за посиланням.
5 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів