Регресионното тестване е процес на повторна проверка на приложението след извършване на промени за откриване на дефекти в предишно работещата функционалност. Всяка промяна на код — нова функционалност, поправка на бъг или рефакторинг — може непреднамерено да счупи съществуващите възможности на приложението. Регресионните тестове автоматизират проверката, че старата функционалност е останала работеща. Според проучване на IBM, 2023, регресионното тестване обхваща от 30 до 70% от всички изпълнявани тестове в търговските продуктови екипи, което подчертава неговата роля като основна бариера срещу производствени инциденти.
Основни точки
Регресионното тестване е вид тестване, насочено към потвърждаване, че промените в кода не са нарушили съществуващата функционалност. Терминът „регресия“ означава връщане към по-лошо състояние — когато функция, работеща в предишната версия, спре да работи в новата. Регресионните тестове се изпълняват многократно във всеки цикъл на разработка, което ги отличава от тестовете на нова функционалност, които се пишат еднократно.
Необходимостта от регресионно тестване произтича от ефекта на каскадни промени: поправката на бъг в един модул може да реши проблема, но да счупи съседната функционалност, която зависеше от него. Например, промяна на SQL заявка в хранилището на потребители може да ускори влизането, но да счупи експорта на данни, който използваше същата заявка. Регресионен тест на експорта на данни ще открие това нарушение преди пускането.
Според доклада на CISQ 2023, цената за поправка на регресионен дефект, открит в продукция, е 15 пъти по-висока отколкото на етапа на автоматизиран регресионен прогон. Компаниите, инвестиращи в автоматизирано регресионно тестване, намаляват дела на регресионните дефекти в пусканията от 25% до 5% в рамките на една година след внедряване, според Capgemini World Quality Report.
Съществуват няколко подхода за регресионно тестване, различаващи се по обем и критерии за подбор на тестове. Изборът на подход зависи от размера на проекта, честотата на промените и наличното време в CI тръбопровода. По-долу са представени основните видове регресионно тестване с техните характеристики.
Пълният регресионен прогон изпълнява всички автоматизирани тестове на проекта без изключение. Този подход дава максимална увереност, но изисква значителни изчислителни ресурси и време. Пълният прогон се изпълнява преди големи пускания — веднъж на 2–4 седмици. За приложение с 5000 теста, пълният прогон отнема от 2 до 6 часа в зависимост от инфраструктурата.
Избирателният подход стартира само тестове, свързани с променените модули. За определяне на свързаността се използва анализ на зависимости на ниво код: ако класът UserRepository е променен, се стартират тестове, зависещи от UserRepository директно или транзитивно. Инструментите Jacoco, Android Test Coverage и Xcode Code Coverage предоставят карти на покритие за точен подбор. Избирателният прогон се изпълнява при всеки pull request и отнема 5–15 минути.
Risk-based регресия класира тестовете според критичността на функционалността и вероятността от счупване. Критичните функции — плащане, оторизация, синхронизация — се тестват при всяка промяна на код. Помощните функции — екран „За приложението“, анимации — се тестват само преди пускане. Класирането се преразглежда на тримесечие на база данни за производствени инциденти.
Често понятията за регресионно тестване и ретест се бъркат, въпреки че са различни процеси. Ретестът е повторно стартиране на конкретен тест, който преди това е паднал, след поправка на дефекта. Целта на ретеста е да се увери, че поправката работи: бъгът вече не се възпроизвежда. Ретестът се изпълнява еднократно, веднага след поправката и потвърждението на поправката от разработчика.
Регресионното тестване е стартиране на тестове върху съществуваща функционалност, която НЕ е променяна. Целта е да се увери, че поправката на един дефект не е създала нов дефект на друго място. Регресионните тестове се стартират многократно във всеки цикъл на разработка, независимо от това кои конкретни бъгове са били поправяни. Основната разлика: ретестът проверява самата поправка, регресията проверява последствията от поправката.
В CI/CD тръбопровода и двата процеса се изпълняват последователно. След сливане на pull request се стартира ретест на конкретния бъг, а след това пълен или избирателен регресионен прогон. Според SmartBear (2022), разделянето на тези процеси намалява времето за диагностика на неуспешни CI прогони с 30%, тъй като екипът веднага вижда коя част от дефектите е свързана с регресия и коя с неработещи поправки.
Автоматизацията на регресионното тестване е критичен фактор за успех за съвременните мобилни проекти. Ръчното регресионно тестване не се мащабира: при набор от 200 теста за един прогон са необходими 2–3 работни дни на QA инженер, което прави ежедневните прогони невъзможни. Автоматизираните регресионни тестове се изпълняват за 10–60 минути без човешко участие, което позволява стартирането им при всеки commit или pull request.
За поддържане на регресионния набор в актуално състояние се използва тестова аналитика: инструменти като Allure, ReportPortal и Xray проследяват процентите на преминаване, продължителността и стабилността на всеки тест. Тестовете, чиято стабилност падне под 90% (често се чупят поради промени в изискванията), се маркират като legacy и се изпращат за преглед на собственика.
Нека разгледаме настройката на автоматизиран регресионен тест на Android с използване на библиотеката JUnit 5 и Espresso. Примерът демонстрира избирателна регресия — тестът проверява, че след рефакторинг на хранилището на потребители не е счупен екранът на профила. За iOS се използва XCTest с аналогична логика — повтарящ се тест на ключовия сценарий.
Тестът използва MockWebServer за емулация на сървър и проверява пълния път: зареждане на данни за потребителя, показване на екрана на профила и обработка на грешка при недостъпен сървър. Такива тестове се включват в регресионния набор и се изпълняват при всяка промяна в module-profile.
@RunWith(AndroidJUnit4::class)
class ProfileRegressionTest {
@get:Rule
val composeRule = createComposeRule()
@Test
fun profileScreen_rendersCorrectly() {
val user = User(id = 1, name = "Alice", email = "alice@test.com")
composeRule.setContent {
ProfileScreen(user)
}
composeRule.onNodeWithText("Alice").assertIsDisplayed()
composeRule.onNodeWithText("alice@test.com").assertIsDisplayed()
}
@Test
fun profileScreen_handlesNetworkError() {
setNetworkError()
composeRule.onNodeWithText("Грешка при зареждане").assertIsDisplayed()
}
}
За iOS регресионният тест използва XCTestExpectation за асинхронна проверка на обновяване на UI след получаване на данни от API. Тестът емулира мрежов отговор и проверява, че UI елементите са се обновили коректно.
class ProfileRegressionTests: XCTestCase {
func testProfileScreen_rendersCorrectly() {
let viewModel = ProfileViewModel(userId: 1)
let view = ProfileView(viewModel: viewModel)
viewModel.loadProfile()
let expectation = expectation(description: "profile loaded")
viewModel.onProfileLoaded = {
XCTAssertEqual(viewModel.userName, "Alice")
XCTAssertEqual(viewModel.userEmail, "alice@test.com")
expectation.fulfill()
}
waitForExpectations(timeout: 3.0)
}
}
Изграждането на ефективен регресионен набор е итеративен процес, основан на данни за дефекти и промени в кода. Първичната стратегия е да включите всички съществуващи тестове в регресионния набор и да стартирате пълен прогон преди всяко пускане. С нарастване на тестовата база (над 2000 теста) пълният прогон става твърде дълъг и се изисква избирателен подход.
Втората фаза — въвеждане на инструменти за анализ на зависимости: Jacoco за Android, Xcode Test Plan за iOS. Тези инструменти изграждат карта „тест — клас — метод“ и позволяват да се определи кои тестове са засегнати от конкретна промяна. Избирателният прогон, основан на анализ на покритие, намалява времето за изпълнение с 60–80% при запазване на 95% ефективност на откриване на регресии, според Spotify Engineering (2022).
Третата фаза — непрекъснат мониторинг и оптимизация. Тестовете, които не са паднали 6 месеца, се преместват в нископриоритетен набор. Тестовете, падащи по-често от веднъж месечно, са кандидати за преглед: или хващат реални проблеми (изискват поправка), или са твърде крехки (изискват стабилизация). Тримесечната ревизия на регресионния набор е стандартна практика за поддържане на неговата ефективност и скорост на изпълнение.
Често задавани въпроси
Избирателен регресионен прогон — при всеки pull request. Пълен регресионен прогон — преди всяко пускане и седмично (nightly build). Ключово правило: колкото по-често стартиране, толкова по-бързо се откриват регресиите и толкова по-ниска е цената за тяхното поправяне. За критични проекти е възможна пълна регресия при всяко сливане.
Всички модулни тестове (базова регресия), интеграционни тестове на ключови компоненти и UI тестове на критични потребителски сценарии. Не включвайте тестове на експериментална функционалност, тестове с flakiness над 10% и тестове, изискващи ръчна среда.
Премахвайте тестове на премахната функционалност, актуализирайте тестовете при промяна на изискванията, провеждайте тримесечен одит на набора. CI аналитика — Allure, ReportPortal — помага да се идентифицират тестове, загубили актуалност: ако тест не се е променял и не е падал 3 месеца, той е кандидат за премахване от ежедневния прогон.
Използвайте паралелно стартиране на тестове на няколко устройства, въведете избирателна регресия на база анализ на покритие на променения код, изключете визуални снимки за нерелевантни екрани. Целево време за избирателен прогон — 5–10 минути, за пълен — не повече от 2 часа.
Не, регресионното тестване включва също ръчни проверки: изследователско тестване след пускане, UX регресия и проверка на достъпност след промяна на интерфейса. Автоматизацията покрива 70–80% от регресионните проверки; останалите 20–30% са ръчни тестове, фокусирани върху сценарии, които не могат или са твърде скъпи за автоматизиране.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също