DevSecOps16 мин

Тестове, които наистина хващат грешки: отвъд покритието и зеления quality gate

От Dorian Chávez · основател на Hábil и архитект по интеграция ·

Високо покритие и зелен quality gate не стигат: видове тестове, двойници, които крият грешки, мутации, ИИ и документация за тестове, които хващат грешки.

Илюстративен сценарий. Екип по плащанията във финтех компания отваря таблото в петък: покритието от тестове е 91 %, анализът на качеството на кода показва зелено и pipeline-ът —автоматичната линия, която изгражда, тества и предава софтуера— приключи без грешки. В понеделник група клиенти съобщават за двойно таксуване. Никой не е излъгал и никой инструмент не се е повредил: всеки е измерил онова, което умее да измерва. Онова, което никой не е измерил, е дали тестовете, които бяха много, биха предупредили именно за този дефект.

Тази статия е за онзи, който отговаря за тази разлика: CTO или директорът по технологиите на банка, финтех, застрахователна компания, търговска верига или регулирана компания. Обяснява какво всъщност измерват покритието и quality gate («вратата за качество»: набор от условия, които кодът трябва да изпълни, за да напредне), какви видове тестове съществуват и каква грешка хваща всеки, как се проверява, че един тест върши работа, каква роля играят изкуственият интелект и документацията на кода и откъде да се започне. Включва онова, което сме измерили в собствената си платформа, защото някои от тези открития бяха неудобни.

Какво всъщност измерва едно зелено табло

Добре е да се започне с това, което казват самите инструменти.

Покритието отговаря на един-единствен въпрос: този ред код изпълнен ли е, докато са се изпълнявали тестовете? SonarQube, инструмент за анализ на качеството на кода, определя покритието на редове като покрити редове, разделени на изпълними редове, а покритието на условия — като обходените истински и фалшиви клонове, разделени на удвоения брой условия [11]. Да се изпълни един ред не е да се провери, че върши правилното: тест без никаква проверка («assertion», сравнението между очакваното и случилото се) може да повиши покритието, без нищо да хване.

Quality gate на SonarQube е набор от настройваеми условия. Стандартният, наречен «Sonar way», изисква в новия код: без нови проблеми, покритие от поне 80 %, дублиране до 3 % и прегледани чувствителни от гледна точка на сигурността места [10] [Данни на Sonar: стойности по подразбиране на доставчика]; всяка организация ги настройва. Покритието на редове казва само дали един ред е изпълнен; общата метрика на Sonar съчетава редове и условия. Освен това Sonar не генерира покритието: внася го от друг инструмент, който изпълнява тестовете преди анализа [12]. От онова, което измерва, се извежда онова, което не прави: не изпълнява превод, нито съгласуване, нито издаване на полица, нито плащане в електронната търговия. Това четене е наше, не е фраза на Sonar, но е съгласувано с онова, което описва документацията му.

Няма и магическо число за покритие. Martin Fowler, водеща фигура в софтуерното инженерство, го смята за инструмент за откриване на непроверен код, не за цел; намира за разумно покритие от високите осемдесет или деветдесет, третира 100 % като сигнал за тревога и предупреждава, че налагането на минимум подканя към писане на празни тестове, за да се достигне до него [9]. Класическо академично изследване на Inozemtseva и Holmes (2014) установява, че покритието няма силна корелация с ефективността на набор от тестове, след като се отчете неговият размер [21].

А «зеленото» означава различни неща според това кой настройва вратата. При вътрешен преглед на нашата платформа установихме, че анализът на току-що създаден проект минаваше с 3 активни условия, докато този на зрял проект изискваше 14. Един и същ цвят, две много различни нива на взискателност.

Двете най-чести форми на фалшиво зелено

1. Двойниците, които отговарят онова, което Вие очаквате

За да тестват бързо, екипите заменят външните части —базата данни, доставчика на плащания, друга услуга— с тестови двойници: имитации, които отговарят по предварително зададен начин. Fowler разграничава няколко вида: stubs (готови отговори), fakes (опростени, но работещи реализации), spies (които записват как са били ползвани) и mocks (които носят предварително програмирани очаквания) [8]. Полезни са, за да остават тестовете бързи и изолирани.

Рискът е лесен за изказване: ако двойникът отговаря онова, което програмистът вярва, че отговаря реалната система, тестът минава, дори реалната система да отговаря друго. Един двойник може да отговори «200 OK», докато реалният доставчик отхвърля хедъра, кодирането, сертификата или формата на датата. Fowler отбелязва още, че тестовете, основани на mocks, са по-силно свързани с реализацията: ако реорганизирате кода, без да променяте онова, което върши, тези тестове се чупят; а ако реалната система се промени, те продължават да минават [7].

Затова тестовете трябва да се доближат до реална свързаност там, където решението го взима зависимостта, а не Вашият код: базата данни с реалния си двигател, шината за съобщения със своята, договорът с доставчика — проверен спрямо доставчика. За зависимостите, които може да контейнеризирате, инструменти като Testcontainers вдигат реална и еднократна база данни или опашка, докато върви тестът, и ги унищожават накрая; собственото им ръководство предлага да се заменят базите данни в паметта с реалната база [13]. За външни доставчици продължавайте да ползвате sandbox, договор или наблюдаем двойник: контейнерът не замества идентификационните данни, хомологацията или разрешението на реална трета страна.

2. Тестовете, които благославят грешката

Тест, написан по онова, което кодът прави, а не по онова, което трябва да прави, удостоверява дефекта. Прост пример: бизнес правилото казва, че се блокират суми от 10 000 песо или повече, но кодът блокира само по-големите от 10 000, а тестът, написан с поглед към кода, проверява сегашното поведение. Има пълно покритие, всичко е зелено и правилото се нарушава. Това е известен риск при тестовете, написани от хора, и, както ще видим, по-голям риск при онези, които пише ИИ.

Нито една от двете форми не се вижда в таблото. Виждат се, като се задават други въпроси на набора от тестове, и за това става дума в останалата част на статията.

Видовете тестове и грешката, която всеки може да хване

Нито един вид тест не покрива сам всички относими рискове. Всеки вид може да даде доказателство, което другите не дават за този поток. Ето списъка, който ползваме, за да го обясним на един комитет:

Видовете тестове и грешката, която всеки може да хване
ВидКакво изпълняваКакво може да хванеКакво не виждаПримерни инструменти
Модулен (unit)Една изолирана функция или класИзчисления, граници, валидации, местни правилаДали частите си пасват една с другаJUnit, pytest, Go testing, Jest, Vitest
Интеграционен с реални зависимостиВашият код плюс реална и еднократна база данни, шина или услугаСчупени миграции, заявки, които се провалят спрямо реалната схема, сериализация, конфигурация, транзакцииПълни потребителски потоциTestcontainers
Договорен (contract)Потребителят (consumer) и доставчикът на едно API, всеки спрямо договоренотоПреименувано поле, променен тип, различен хедър, които биха счупили потребителяВътрешната логика на доставчикаPact
Колекция за APIHTTP заявки спрямо една среда, с проверкиКодове на отговора, формати, автентикация, авторизация, регресии на една услугаВътрешното поведениеPostman, Postman CLI, Newman
В браузър (от край до край)Симулиран човек, браузърът, фронтендът и бекендът, интегрираниМаршрути, бисквитки, вход в системата, визуализиране, критични потоциФини детайли; бавни са и крехки, ако се злоупотребява с тяхPlaywright
С мутацииВашият набор от тестове срещу умишлено повредени версии на кодаТестове, които изпълняват код, без да откриват промениДали самото бизнес правило е правилнотоPIT (Java), Stryker (JavaScript/TypeScript, C#, Scala)

Няколко уточнения, които имат значение при решаването:

  • Договорни тестове. Pact проверява доставчика, който екипът контролира; не валидира непременно реалната трета страна. Работи «воден от потребителя»: проверява се само онова, което потребителят наистина ползва; потребителят генерира файл със своите очаквания, а доставчикът го проверява спрямо реалната услуга [14]. Избягва скъпите интегрирани тестове между два екипа. Собствените му документи декларират границите му: не служи за функционални тестове, за натоварване, за публични API, нито когато не се контролират и двете страни [14].
  • Колекции за API. Postman позволява писане на проверки на JavaScript за всяка заявка, папка или колекция [15]. Практическа подробност, която малцина споменават: Newman, изпълнителят на колекции от командния ред, продължава да е наличен за съществуващите потоци, но неговото официално хранилище посочва, че активната разработка се ограничава до основна поддръжка и че за нови потоци препоръчват Postman CLI [16]. Ако вече имате колекции, които работят с Newman, няма спешност; ако ще започвате, добре е да започнете с актуалния инструмент.
  • Браузър. Тестът в браузър не винаги е от край до край: може да симулира трети страни. Playwright покрива Chromium, WebKit и Firefox, а добрите му практики изискват да се тества онова, което вижда потребителят, всеки тест да се изолира и външните сайтове да се симулират, вместо да се тестват [17]. Това е видът, най-близък до реалната употреба, и затова се запазва за малко на брой пътища с висока стойност.
  • Мутации. Обяснява се с едно изречение: умишлено се саботира системата, за да се види дали ще прозвучи алармата. Развива се по-нататък.

Инструменти по слой

Видовете тестове и грешката, която всеки може да хване
СлойПримерни инструментиЗа какво
Java бекендJUnit, Testcontainers, PITБизнес правила, интеграция с инфраструктурата, мутации на критичния код
Python бекендpytest (със своите fixtures, данни и ресурси за подкрепа, които могат да се ползват повторно)Правила, параметризиране, интеграция
Go бекендtesting и go test, част от стандартната библиотека; допуска тестове с fuzzing (случайни входове)Модули, интеграция, неочаквани входове
Фронтенд (JavaScript/TypeScript)Jest или Vitest, с Testing LibraryЛогика на интерфейса и компоненти, тествани така, както ги ползва човек
Фронтенд, пълни пътищаPlaywrightКритични потоци и съвместимост между браузъри
JavaScript/TypeScript, мутацииStrykerJS върху Jest или VitestОткриване на слаби тестове

Testing Library формулира принципа ясно: колкото повече един тест прилича на начина, по който се ползва софтуерът, толкова повече доверие дава [20]. Jest декларира, че Vite не се поддържа официално, и в този случай предлага Vitest [20]; това е пример защо инструментът се избира според останалата част от стека, а не според модата.

Защо повече видове тестове носят повече от повече тестове от същия вид

Правилното твърдение не е «колкото повече видове, толкова по-добре» без граница. То е това: за даден риск си струва да се инвестира във вида тест, който покрива клас грешки, още непокрит от никого.

Още десет модулни теста върху едно закръгляване няма да открият миграция на база данни, която се проваля, несъвместим HTTP договор, загубена между екраните сесия или зависимост, която се бави прекалено. Това го откриват други видове. Изследователските данни за разнообразието на тестовете вървят в тази посока: критерии, които различават различни поведения, могат да намерят грешки, които традиционните критерии не виждат, срещу допълнителен разход [23].

Другата половина на равновесието е да не се отива в обратната крайност. Тестовете в браузър са най-близките до реалната употреба, но и най-бавните и крехки. Fowler ги описва като крехки, скъпи за писане и бавни за изпълнение [1]. В проучването на Google върху около 4,2 милиона собствени теста най-големите са били по-нестабилни, тоест минават и се провалят, без кодът да се променя; WebDriver и емулаторът на Android показват честоти над средните сред анализираните инструменти, а авторът изрично отбелязва, че корелацията не е причинност [5] [Данни на Google, 2017; не са универсални]. Ръководството им препоръчва, приблизително, 70 % малки тестове, 20 % интеграционни и 10 % от край до край [4] [Данни на Google, 2015; не са универсални]. Това е ориентир на една компания, не норма; има и такива, които твърдят, че обсъждането на проценти отвлича вниманието [3]. Fowler и Google препоръчват широките тестове да се пазят за рисковете, които го оправдават; пропорцията зависи от системата, а Fowler предупреждава, че пирамидата има изключения [1][4].

Един пример за комитет: три хиляди модулни теста с двойници, без договорни тестове, означават, че едно преименувано поле в едно API чупи всички негови потребители в продукция, без никое табло да предупреди. Същите три хиляди, без реална интеграция, означават, че никой не е тествал заявката спрямо истинската схема. А ако всичко това съществува, но никой тест не минава през целия поток, никой не знае дали клиентът може да завърши покупката си. Всеки вид тест може да покрива клас грешки, които другите не виждат; да се съсредоточи всичко в един вид е да се съсредоточи рискът.

Онова, което сме измерили в собствената си платформа

Hábil изгражда модулна платформа за интеграция. При скорошно измерване, върху нейните 34 услуги, преброихме 1407 тестови класа и около 9800 автоматизирани тестови метода (два различни начина на броене дадоха 9771 и 9839) [37]. С такова количество човек би очаквал да е спокоен. Ето поуки, вече коригирани, от случаи, в които спокойствието беше неоснователно. Числата са наши и не са одитирани външно.

Плащането, което се извършваше 12 пъти. Един тест на един поток за плащания се казваше «не дублира» и беше зелен. Проверяваше вътрешен брояч на самата услуга, а не повикването към доставчика на плащания. Когато го пренаписахме да проверява реалното повикване, се провали: очакваше се 1 и станаха 2. С фалшив сървър, който брои колко пъти го извикват, 12 едновременни опита произведоха 12 плащания. След поправката произведоха 1. Забележете разликата между два класа двойници: единият отговаря онова, което се очаква, и крие дефекта, а другият записва онова, което наистина му идва, и го разкрива.

17-те от 19 загубени полета. Една промяна във функция за извличане на данни мина през целия набор от тестове, който ползваше синтетични примерни документи. С реални документи промяната губеше 3 от 4 полета при един вид документ и 17 от 19 при един чуждестранен документ. Тестовете не бяха зле написани: бяха захранени с данни, които не приличаха на реалните.

Отказът, който прекъсваше един канал. Един легитимен отказ на доставчика, повторен няколко пъти, задействаше прекъсвача (circuit breaker), механизма, който прекъсва повикванията към услуга, която изглежда паднала. Резултатът беше прекъсване на целия канал. Присъстваше в 7 услуги. Тестовите двойници не повтаряха отказа, така че дефектът нямаше откъде да се появи.

Пет зелени теста, които поддържаха дефекти. Намерихме пет зелени теста, които поддържаха дефекти, от три вида: онзи, който благославя грешката с изрично име, онзи, който симулира невъзможен изход, и твърде толерантният. Изпълнението на реалната система отхвърли 9 наши находки и потвърди други: проверката на живо поправя в двете посоки.

Успехът без работа. Две фалшиви зелени при измерване, от най-коварните: един билд, който завърши със съобщение за успех, без да е изпълнил нито един тест, и едно изпълнение на тестове, прекарано през текстов филтър, който прекъсна процеса по средата и отчете 113 и 401 теста, където в действителност се изпълняваха 518. Изходът изглеждаше като валидно преброяване. Урок: броят на тестовете се чете от отчета, а не от изходния код на командата.

Петте случая имат обща основа: във всеки от тях зеленият сигнал беше добре построен и отговаряше честно на въпроса, който му се задаваше. Въпросът беше погрешният.

Как се разбира дали един тест върши работа?

Има два отговора, един занаятчийски и един автоматизиран.

Занаятчийският: да се върне поправката назад и да се види тестът в червено. Ако един тест е написан, за да пази една поправка, поправката се отменя и тестът се пуска: трябва да се провали. Ако остава зелен, не е пазел нищо. За нов дефект равностойното правило е първо да се напише тестът, който се проваля, и после да се поправи; официалното ръководство на Claude Code, например, го изисква така за грешките [28]. Евтино е и изисква дисциплина. В нашата платформа го ползваме като мярка: 6-те ръчни мутации, които направихме, бяха открити.

Има една по-фина клопка, която е добре да се знае, защото не се появява в литературата, която прегледахме: един тест може да мине и с дефекта. При една от нашите поправки критерият казваше «след отказа салдото се връща към предишната си стойност». При прегледа забелязахме, че тази проверка минаваше и с грешката, защото отделянето на сума и връщането ѝ оставят същото число. Онова, което наистина различаваше, беше регистърът на операциите: с дефекта се появяваха два записа; с поправката — нито един. Въпросът, който си струва да се зададе на всеки важен тест, е прост: би ли минал и ако грешката още беше там?

Автоматизираният: тестването с мутации. Инструменти като PIT (за Java) и Stryker (за JavaScript, TypeScript, C# и Scala) променят автоматично кода —сменят «по-голямо от» с «по-голямо или равно», обръщат условие, премахват повикване— и пускат набора от тестове [18][19]. Ако някой тест се провали, промяната «умира»; ако всички минат, промяната «оцелява» и разкрива тест, който е липсвал. Процентът на открити промени се нарича mutation score: ако от 100 саботажа наборът хване 80, резултатът е 80 %. PIT го казва ясно: традиционното покритие измерва само какво се изпълнява, не дали тестовете биха могли да открият грешка [18]. Проучване от FSE 2014 установява, че мутантите са валиден заместител на реалните грешки при оценяване на тестове [22].

Мутациите имат ограничения, които един CTO трябва да знае:

  • Бавни са. Затова е добре да се прилагат към кода, който се е променил, или към критичния код, а не към цялото хранилище; документацията на самия PIT го препоръчва [18].
  • Имат шум. Съществуват «еквивалентни мутанти»: промени, които не променят поведението и които никой тест не би могъл да открие [18]. Индустриално проучване отчита, че автоматичното откриване на такива мутанти се подобрява много с предварителна обработка, което показва, че самият контрол има своя граница на грешка [27].
  • Не удостоверяват бизнеса. Ако тестът благославя погрешно правило, може дори да «убие» промяната, която поправя кода. Изследванията подкрепят ползването на мутациите като ориентир, не като единствен показател: връзката им с реалните дефекти зависи от размера и контекста на набора от тестове [23].

Затова качеството се измерва като набор от сигнали, всеки със своя въпрос:

Как се разбира дали един тест върши работа?
СигналВъпрос, на който отговаря
ПокритиеКой код е изпълнен?
МутацииОткриват ли проверките правдоподобни промени?
Проверени договориПотребителят и доставчикът все още ли са съвместими?
API и браузър в критични пътищаРаботи ли реалният поток в целевата среда?
Проследимост между изискване и тестОчакването идва ли от одобрено правило, или от онова, което кодът вече е правел?
Дефекти, стигнали до продукцияДоказателствата продължават ли да предсказват онова, което се случва в продукция?

Дори с реална свързаност могат да се случат неща

Привеждането на тестовете към реални зависимости намалява един клас риск; не го премахва. Една тестова среда не е продукция: има по-малко данни, друга латентност, други идентификационни данни и, често, друга версия на доставчика. Трета страна може да промени поведението си без предупреждение. Едно натоварване, което не е било симулирано, може да покаже дефект при паралелност. А потоците, които се случват само веднъж месечно, като счетоводното приключване или годишното подновяване на една полица, рядко са в набора от тестове. Тази карта покрива главно функционалното поведение и съвместимостта; производителността, сигурността и непрекъснатостта изискват специфични контроли според риска.

Затова разумната стратегия има две половини. Първата, повече видове автоматизирани тестове, всеки насочен към клас грешки. Втората, онова, което става след пускането: да се наблюдава какво прави системата, да може да се върне назад и да се прегледа спокойно онова, което е избягало. Всеки дефект, стигнал до продукция, е информация: показва какъв вид тест е липсвал, и правилният отговор обикновено е да се добави този тест, не само да се поправи кодът. Този разговор, за пускането с контрол, го развиваме в «Пускайте версии без страх в собствената си инфраструктура».

Изкуственият интелект: ускорява, но се нуждае от филтър

ИИ помага да се построят тестове: предлага гранични случаи, генерира скелети, сглобява колекции за API, обяснява една грешка. Производството му има известен профил.

Какво показват данните. Индустриално проучване на Meta за генериране на тестове с езикови модели отчита, че 75 % от случаите са се компилирали, 57 % са минавали надеждно и 73 % от препоръките са били приети от инженерите [Проучване на Meta, конкретна извадка]; всичко това след автоматични филтри, които изхвърлят онова, което не се компилира, не минава или не добавя покритие [24]. Проучване върху 25 пакета на JavaScript установява медиана от 70,2 % покритие на оператори (statements) и 52,8 % на клонове (branches) с един модел с общо предназначение [25]. Това са цифри за модели от 2023 и 2024 г.; днешните ще са различни, но посоката е поучителна: без филтри значителна част от генерираното не върши работа.

Основният риск. ИИ е склонен да копира онова, което кодът прави, а не онова, което трябва да прави. Проучване върху 24 хранилища на Java заключава, че тестовете, генерирани с езикови модели, улавят предимно сегашното поведение, което затруднява откриването на грешки [26]. Това е тестът, който благославя грешката, произведен със скоростта на машина. Други документирани рискове: повърхностни проверки, които надуват покритието, измислени методи или правила и чувствителни данни, които излизат към трета страна. Едно историческо проучване на асистент за код е намерило уязвимости при около 40 % от 1689 програми, генерирани за конкретни сценарии; това е резултат от своето време, не честота, приложима към днешните модели [36].

Какво да се прави с това. Ръководствата на доставчиците съвпадат в същественото, макар нито едно да не носи собствени цифри:

  • Да се даде на ИИ проверка, която той сам може да изпълни; ръководството на Claude Code я нарича разликата между сесия, която се наблюдава, и такава, която се оставя сама, и изисква да показва изхода от тестовете, вместо да твърди, че са минали [28].
  • Да се бъде конкретен при искането на тестове: «добави тестове към този файл» е лошият пример; добрият назовава граничния случай и онова, което трябва да се избегне [28].
  • Да се прегледа генерираното и да се добавят тестовете, които липсват, както указва ръководството на GitHub Copilot [30].
  • Да се следи за «насилствено постигнатото зелено»: ръководството на Anthropic предупреждава, че моделът може да се фокусира върху това тестовете да минат, дори с твърдо зададени стойности, и напомня, че тестовете са за проверка на коректността, не за определяне на решението [29].
  • Да се отделят онзи, който пише, от онзи, който преглежда. Ръководството на Claude Code предлага различни сесии за писане на тестовете и за писане на кода, който ги удовлетворява [28].
  • Да не се зареждат производствени данни в инструменти с ИИ или в тестови среди без класификация, маскиране (или синтетични данни) и проверка на поверителността, а с доставчика да се уточнят съхранението и договорните условия.
  • Да се прекара генерираното през мутациите: даването на ИИ на оцелелите мутанти е позволило да се открият до 28 % повече дефектни фрагменти от код, написан от хора, отколкото базовата линия, в едно проучване [27].

Политиката, която обобщава всичко, е кратка: ИИ предлага; изпълнението, мутациите и прегледът от предметната област валидират.

Защо документирането на кода подобрява тестовете

Кодът казва само онова, което прави. Онова, което трябва да прави, живее другаде, и ако не е записано, ИИ —и новият човек в екипа— го извежда от реализацията и копира грешките ѝ. Тук влиза документацията.

Коментарите за документация —Javadoc в Java, JSDoc и TSDoc в JavaScript и TypeScript, docstrings в Python— са, на практика, договор: какво получава една функция, какво връща, какви изключения може да хвърли, какви странични ефекти има [34]. Конвенцията на Python (PEP 257) изисква да се документират поведение, аргументи, върната стойност, странични ефекти, изключения и ограничения при употреба [34]. Освен това doctest превръща примерите, написани в docstring, в изпълними тестове: ако един пример престане да е верен, наборът от тестове го казва [34]; онова, което docstring обяснява извън тези примери, може да остарее мълчаливо.

Колко доказателства има, че това подобрява тестовете? Честният отговор е: сочи в тази посока, макар да не сме намерили чист експеримент «същият код със и без документация». Съществуват близки проучвания: превръщането на документация на естествен език във проверими условия с езиков модел е позволило да се уловят 64 реални исторически грешки [33]; извличането на правила от документацията на API за дълбоко обучение е намерило 94 грешки срещу 59 на базовата линия без тези ограничения [33]; а проучване за генериране на проверки установява подобрения от 10 до 20 % при включване на Javadoc [31]. Предупреждението е в обратната посока: фалшива или остаряла документация може сериозно да навреди на разбирането на кода от един модел [32]. Не стига да се документира; трябва онова, което е документирано, да се поддържа вярно.

Третият елемент са контекстните файлове на хранилището, като AGENTS.md (отворен формат, който четат няколко асистенти за код, между които Codex и Copilot) или CLAUDE.md при Claude Code [35]. В тях се записват командите за пускане на тестовете, конвенциите и клопките, които не се извеждат от четенето на кода. Две официални препоръки: да са кратки, защото ако са дълги, асистентът игнорира правила, и да не заместват одобрените изисквания, нито да съдържат тайни [28][35].

В нашата платформа документираме кода, за да може един нов човек да се ориентира без помощ. Нямаме измерено това да е подобрило тестовете, които пишат асистентите, и не го твърдим. Онова, което измерихме, е цената на това да не се напише: документацията вече казваше, че една конфигурационна опция не се упражнява извън стойността си по подразбиране, а пропускът в покритието се появи въпреки това. От това излезе едно практическо правило: тест за конфигурация трябва да демонстрира двете посоки, не само обичайната.

Прости примери по отрасъл

Всички са илюстративни сценарии, без клиенти и без цифри.

Прости примери по отрасъл
ОтрасълСценарийКаква комбинация от тестове го хваща
БанкиЕдин превод се дублира, когато приложението повтаря след прекъсната връзкаМодулен за идемпотентността (повторението на една и съща операция повторният опит не я прилага втори път); интеграционен с реалната база, за да се провери, че ограничението за уникалност работи; договорен с услугата за плащания; път в браузър от превода до разписката
ФинтехЕдин депозит се заверява два пъти, когато доставчикът повтаря известиетоМодулен за ключа за идемпотентност и сумите; интеграционен с реалната книга на салдата; договорен за известието; колекция за API за невалидния подпис
ЗастрахованеОфертата прилага погрешно самоучастие точно на граничната възрастМодулен с гранични възрасти (70 и 71, със и без медицински преглед); мутации на тарифния двигател, защото там замяната на «по-голямо от» с «по-голямо или равно» променя премиите; път от офертата до издаването
РитейлCheckout продава последната бройка на двама клиенти едновременноИнтеграционен с реалните наличности и паралелност; договорен с плащанията; няколко теста в браузър за пътя на покупката, със симулиран външен платежен шлюз
Регулирана компанияЕдин регулаторен отчет показва погрешно агрегирана сумаМодулни за правилата за изчисление; интеграционен спрямо реалната схема; мутации върху логиката на агрегиране; изискване, записано в контекста на хранилището, което да налага тест за маскиране на лични данни в дневниците

Вземете примера с банките. Модулният казва, че логиката е вярна; интеграционният показва, че базата наистина отхвърля дубликата; договорният казва, че услугата за плащания разбира същия идентификатор; този в браузър — че човекът вижда разписка. Нито един от четирите, сам, не дава доказателството на останалите три.

От къде да започнете

  1. Измерете онова, което вече имате, по два начина. Пребройте тестовете си от отчета на изпълнението, не от изходния код, и го сравнете с друг метод. Прегледайте какви активни условия има Вашият quality gate във всеки проект и дали са едни и същи.
  2. Изберете петте си потока с най-много пари или най-много регулация в играта —плащане, издаване, съгласуване, отчет— и за всеки попитайте: какъв вид тест би го хванал, ако се счупи, и съществува ли днес?
  3. Прегледайте двойниците си. Там, където решава зависимостта (база, шина, доставчик), преминете от двойник, който отговаря онова, което се очаква, към реална зависимост или към двойник, който записва онова, което наистина пристига.
  4. Изпробвайте тестовете си. Изберете десетте най-важни: върнете поправката назад и проверете, че стават червени. В критичния код преценете инструмент за мутации, ограничен до онова, което се променя.
  5. Поставете ИИ в същия контрол. Да показва изхода от тестовете, да не затваря задача с празни проверки и зад всеки генериран тест да стои записано изискване.
  6. Запишете какво трябва да прави системата там, където асистентите го четат: документация на критичните правила и кратък контекстен файл с командите и клопките.

При една диагностика, с уговорен обхват, можем да изградим карта на Вашите критични потоци, на съществуващите доказателства и на приоритизираните пропуски. Тя не замества сертификация за липса на дефекти или за съответствие. Колко от тестовете, които днес поддържат Вашето зелено, стават червени, ако се върне поправката назад? Това е естествената следваща стъпка: диагностиката може да започне с отговора на този въпрос върху Вашите собствени потоци.

Referencias

  1. M. Fowler, Test Pyramid (2012). https://martinfowler.com/bliki/TestPyramid.html
  2. H. Vocke, The Practical Test Pyramid (2018). https://martinfowler.com/articles/practical-test-pyramid.html
  3. K. C. Dodds, The Testing Trophy and Testing Classifications (2018). https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications
  4. Google Testing Blog, Just Say No to More End-to-End Tests (2015). Ръководство на една компания, приблизителни цифри. https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html
  5. Google Testing Blog, Where do our flaky tests come from? (2017). Данни на Google, не универсални. https://testing.googleblog.com/2017/04/where-do-our-flaky-tests-come-from.html
  6. Google Testing Blog, Test Sizes (2010). https://testing.googleblog.com/2010/12/test-sizes.html
  7. M. Fowler, Mocks Aren't Stubs. https://martinfowler.com/articles/mocksArentStubs.html
  8. M. Fowler, Test Double. https://martinfowler.com/bliki/TestDouble.html
  9. M. Fowler, Test Coverage. https://martinfowler.com/bliki/TestCoverage.html
  10. SonarQube, Introduction to quality gates (стойности по подразбиране на доставчика, настройваеми), консултирано на 6 октомври 2026 г. https://docs.sonarsource.com/sonarqube-server/quality-standards-administration/managing-quality-gates/introduction-to-quality-gates
  11. SonarQube, Metrics definition (покритие на редове и на условия), консултирано на 6 октомври 2026 г. https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition
  12. SonarQube, Test coverage overview, консултирано на 6 октомври 2026 г. https://docs.sonarsource.com/sonarqube-server/analyzing-source-code/test-coverage/overview
  13. Testcontainers, документация и ръководства, консултирано на 6 октомври 2026 г. https://java.testcontainers.org/ · https://testcontainers.com/guides/
  14. Pact, документация (How Pact works, What is Pact good for), консултирано на 6 октомври 2026 г. https://docs.pact.io/ · https://docs.pact.io/getting_started/what_is_pact_good_for
  15. Postman, Test scripts и Postman CLI overview, консултирано на 6 октомври 2026 г. https://learning.postman.com/docs/tests-and-scripts/write-scripts/test-scripts/ · https://learning.postman.com/docs/postman-cli/postman-cli-overview/
  16. Newman, официално хранилище (README: ограничена поддръжка; Postman CLI за нови потоци), консултирано на 6 октомври 2026 г. https://github.com/postmanlabs/newman
  17. Playwright, Introduction, Best practices и Mock APIs, консултирано на 6 октомври 2026 г. https://playwright.dev/docs/intro · https://playwright.dev/docs/best-practices · https://playwright.dev/docs/mock
  18. PIT Mutation Testing, сайт, мутатори и FAQ, консултирано на 6 октомври 2026 г. https://pitest.org/ · https://pitest.org/faq/
  19. Stryker Mutator, документация, консултирано на 6 октомври 2026 г. https://stryker-mutator.io/docs/
  20. Официална документация на JUnit, pytest, Go testing, Jest, Vitest и Testing Library, консултирано на 6 октомври 2026 г. https://docs.junit.org/current/user-guide/ · https://docs.pytest.org/en/stable/ · https://pkg.go.dev/testing · https://jestjs.io/docs/getting-started · https://vitest.dev/guide/ · https://testing-library.com/docs/
  21. L. Inozemtseva и R. Holmes, Coverage Is Not Strongly Correlated with Test Suite Effectiveness, ICSE 2014. https://dl.acm.org/doi/10.1145/2568225.2568271
  22. R. Just et al., Are Mutants a Valid Substitute for Real Faults in Software Testing?, FSE 2014. https://dl.acm.org/doi/10.1145/2635868.2635929
  23. M. Papadakis et al., мутации и реални дефекти, ICSE 2018 (https://doi.org/10.1145/3180155.3180183); Shin, Papadakis и Kintis, разнообразие на тестовете и мутации, IEEE TSE (https://doi.org/10.1109/TSE.2017.2732347).
  24. N. Alshahwan et al., Automated Unit Test Improvement using Large Language Models at Meta, FSE 2024, arXiv 2402.09171. https://arxiv.org/abs/2402.09171
  25. Schäfer et al., An Empirical Evaluation of Using Large Language Models for Automated Unit Test Generation, arXiv 2302.06527. https://arxiv.org/abs/2302.06527
  26. Проучване на оракули за тестове, генерирани с езикови модели (24 хранилища на Java), arXiv 2410.21136. https://arxiv.org/abs/2410.21136
  27. Тестове с езикови модели и мутации: arXiv 2308.16557 (оцелели мутанти в prompt, до 28 % повече открити дефектни фрагменти) и arXiv 2501.12862 (насочени мутации в индустрията). https://arxiv.org/abs/2308.16557 · https://arxiv.org/abs/2501.12862
  28. Anthropic, Claude Code, Best practices и Memory, консултирано на 6 октомври 2026 г. https://code.claude.com/docs/en/best-practices · https://code.claude.com/docs/en/memory
  29. Anthropic, Claude prompting best practices, консултирано на 6 октомври 2026 г. https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices
  30. GitHub, Copilot: write tests и Best practices, консултирано на 6 октомври 2026 г. https://docs.github.com/en/copilot/tutorials/write-tests · https://docs.github.com/en/copilot/get-started/best-practices
  31. Liu et al., Doc2OracLL, 2025. https://doi.org/10.1145/3729354
  32. Macke и Doyle, документация и разбиране на код от езикови модели, NAACL Findings 2024. https://aclanthology.org/2024.findings-naacl.66/
  33. Документацията като вход за тестове: arXiv 2310.01831 (nl2postcond: естествен език към проверими условия, 64 реални исторически грешки от Defects4J) и arXiv 2109.01002 (DocTer: правила, извлечени от документацията на API за дълбоко обучение, 94 грешки срещу 59 на базовата линия). https://arxiv.org/abs/2310.01831 · https://arxiv.org/abs/2109.01002
  34. Oracle, спецификация на коментарите Javadoc; JSDoc; TSDoc; PEP 257; документация на doctest, консултирано на 6 октомври 2026 г. https://docs.oracle.com/en/java/javase/21/docs/specs/javadoc/doc-comment-spec.html · https://jsdoc.app/about-getting-started · https://tsdoc.org/ · https://peps.python.org/pep-0257/ · https://docs.python.org/3/library/doctest.html
  35. AGENTS.md (отворен формат) и документация на Codex и GitHub Copilot за инструкциите на хранилището, консултирано на 6 октомври 2026 г. https://agents.md/ · https://learn.chatgpt.com/docs/agent-configuration/agents-md · https://docs.github.com/en/copilot/reference/custom-instructions-support
  36. Pearce et al., Asleep at the Keyboard? Assessing the Security of GitHub Copilot’s Code Contributions, IEEE Symposium on Security and Privacy, 2022 (https://doi.org/10.1109/SP46214.2022.9833571); версия в Communications of the ACM, 2025 (https://doi.org/10.1145/3610721).
  37. Hábil, собствени измервания върху своята модулна платформа (34 услуги), 2026 г. Опит на компанията, без външен одит.