Резюме Програма със сложна структура, използваща менюто - Банка с резюмета, есета, доклади,
време и материални ресурси); Трябва да се вземе предвид така нареченият „принцип на натрупване на грешки“: вероятността да има неоткрити грешки в дадена част от програмата е право пропорционална на броя на вече откритите грешки в тази част; винаги трябва да помните, че тестването е творчески процес, а не да го приемате като рутинна задача. Има два основни типа изпитване: функционално и структурно. При функционално тестване програмата се третира като „черна кутия“ (т.е. нейният текст не се използва). Проверява се съответствието на поведението на програмата с нейната външна спецификация. Възможно ли е да се тества напълно програмата? Очевидно е, че критерият за пълнота на теста в този случай ще бъде изброяването на всички възможни стойности на входните данни, което е невъзможно.
Тъй като изчерпателното функционално тестване е невъзможно, можем да говорим за разработване на методи, които позволяват избор на тестове не „на сляпо“, а с голяма вероятност за откриване на грешки в програмата. При структурно тестване програмата се третира като "бяла кутия" (т.е. нейният текст е отворен за използване). Тества се логиката на програмата. Пълен тест в този случай ще бъде този, който ще доведе до изброяване на всички възможни пътища в графиката за трансфер на управление на програмата (нейната контролна графика). Дори за програми със средна сложност броят на такива пътища може да достигне десетки хиляди. Ако се ограничим до изброяване само на линейни независими пътища, тогава в този случай изчерпателното структурно тестване е практически невъзможно, тъй като не е ясно как да се изберат тестове, за да се осигури „покритие“ на всички такива пътища. Следователно при структурно тестване е необходимо да се използват други критерии за неговотопълнота, което ви позволява просто да контролирате тяхното изпълнение, но не гарантира пълна проверка на логиката на програмата. Но дори да приемем, че е постигнато пълно структурно тестване на някаква програма, тя все още може да съдържа грешки, т.к. програмата може да не отговаря на своята външна спецификация, което по-специално може да доведе до факта, че някои необходими пътища ще липсват в нейната контролна графика; Няма да бъдат открити грешки, чиято поява зависи от данните, които се обработват (т.е. програмата работи правилно на някои първоначални данни и с грешка на други). По този начин нито структурното, нито функционалното изпитване могат да бъдат изчерпателни. Нека разгледаме по-подробно основните етапи на тестване на софтуерни системи. Има четири етапа при тестване на многомодулни софтуерни системи: тестване на отделни модули; съвместно тестване на модули; тестване на функциите на софтуерния пакет (т.е. търсене на разлики между разработената програма и нейната външна спецификация); тестване на целия комплекс като цяло (т.е. търсене на несъответствие между създадения софтуерен продукт и предварително формулираните цели на проектиране, обикновено отразени в техническото задание). На първите два етапа се използват предимно структурни методи за изпитване, тъй като на по-късните етапи на тестване тези методи са по-трудни за използване поради големия размер на тествания софтуер; Последващите етапи на тестване са насочени към откриване на грешки от различен тип, които не са непременно свързани с логиката на програмата. При тестване както на отделни модули, така и на техните комплекси трябва да се решат две задачи: изграждане на ефективен набор от тестове; избор на методкомбинация (сглобяване) на модули при създаване на тествана версия на програмата.
СТРУКТУРНО ИЗПИТВАНЕ.Тъй като изчерпателно структурно изпитване не е възможно, е необходимо да се изберат такива критерии за неговата пълнота, които да позволят простата им проверка и да улеснят целенасочения подбор на изпитвания. Най-слабият от критериите за пълнота на структурното тестване е изискването за поне едно изпълнение (покритие) на всеки програмен оператор. По-силен критерий е така нареченият C1 критерий: всеки клон на алгоритъма (всеки преход) трябва да бъде преминат (изпълнен) поне веднъж. За повечето езици за програмиране покритието на прехода също така осигурява покритие на оператора, но например за програми на езика PL/1, в допълнение към покриването на всички клонове, са необходими всички допълнителни входни точки за процедури (посочени от инструкциите ENTRY) и всички ON-one. Използването на критерия за покритие на условието може да причини избора на тестове, които предоставят преход в програмата, който се пропуска при използване на критерия C1 (например, в програма на Pascal, използваща конструкцията на цикъл WHILE x AND y DO., прилагането на критерия за покритие на условието изисква проверка на двете опции за излизане от цикъла: NOT x и NOT y). От друга страна, покритието на условията може да не покрива всички преходи. Например конструкцията IF A И B THEN. изисква два теста (например A=true, B=false и A=false, B=true ), при които операторът, намиращ се в клона then на оператора if, може да не бъде изпълнен. Практически единственият инструмент, предоставен от съвременните системи за програмиране, е възможността за определяне на честотата на изпълнение на различни програмни оператори (нейното профилиране). Но с товаинструмент за поддръжка на тестове, можете да проверите изпълнението само на най-слабия от критериите за пълнота - покритие на всички твърдения. С помощта на същия инструмент обаче можете също да проверите изпълнението на критерий C1. Но за това текстът на програмата трябва първо да бъде трансформиран по такъв начин, че всички конструкции за условен избор (IF и CASE
или SWITCH ) съдържаше клонове ELSE или DEFAULT, макар и празни. В този случай всички клонове на алгоритъма, които не са били изпълнени при този тест, ще бъдат „видими“ от таблицата на честотата на изпълнение на операторите на трансформираната програма. Актуална е задачата за създаване на инструменти, които позволяват: да се натрупа информация за покрити и непокрити клонове за всички използвани тестове; за разпределяне на разработчиците на области на програмата, които все още не са обхванати по време на тестването, което улеснява избора на следващите тестове; Поддържайте по-мощни критерии за пълнота на структурно тестване.
Съвместно тестване на модули.
Известни са два подхода за съвместно тестване на единици: стъпка по стъпка и монолитно тестване. При монолитно тестване всички модули на софтуерния пакет се тестват поотделно, след което всички те се комбинират в работеща програма за комплексно тестване. При поетапно тестване всеки модул за неговото тестване е свързан с набор от вече тествани модули. В първия случай автономното тестване на всеки модул изисква драйверен модул (т.е. спомагателен модул, който симулира извикването на тествания модул) и един или повече модули - пънове (т.е. спомагателни модули, които симулират работата на модули, извикани от тествания модул). При стъпковото тестване модулите не се тестват изолирано един от друг, така че са необходими или само драйвери, илисамо мъничета.

При сравняване на поетапно и монолитно тестване могат да се отбележат следните предимства на първия подход: по-ниска интензивност на труда (например на фиг. 1 са необходими 5 драйвера и 5 щепсела за монолитно тестване; поетапното тестване изисква или само 5 драйвера - ако модулите са свързани "отдолу нагоре", - или само 5 щепсела - ако модулите са свързани "отгоре надолу") ; по-ранно откриване на грешки в интерфейсите между модулите (сглобяването им започва по-рано отколкото при монолитно тестване); отстраняването на грешки е по-лесно, т.е. локализирането на грешки (те са свързани главно с последния от свързаните модули); по-перфектни резултати от теста (по-задълбочена проверка на споделянето на модула). Монолитното тестване също има предимства: по-малко потребление на машинно време (въпреки че поради по-голямата сложност на отстраняването на грешки може да се наложи допълнителна проверка на програмата и това предимство ще бъде отменено) ; предоставят се повече възможности за организиране на паралелна работа в началния етап на тестване. По принцип поетапното тестване е по-подходящо. При използването му са възможни две стратегии за свързване на модули: низходяща и възходяща. Тестването отгоре надолу започва от основния (или най-горния) модул на програмата и изборът на следващия плъгин става измежду модулите, извикани от вече тестваните. Един от основните проблеми при тестването отгоре надолу е създаването на мъничета. Това е тривиална задача, тъй като обикновено не е достатъчно мъничето да извежда подходящото информационно съобщение и винаги да връща същите стойности на изходните данни. Друг проблем, който трябва да бъде разрешен, когатотестването отгоре надолу е форма на представяне на тестове в програма, тъй като по правило главният модул получава входни данни не директно, а чрез специални входни модули, които се заменят с мъничета по време на тестване в началото. За да прехвърлите различни тестове към главния модул, трябва или да имате няколко различни мънича, или да запишете тези тестове във файл във външна памет и да ги прочетете с помощта на мъниче. Тъй като след тестване на основния модул процесът на тестване може да продължи по различни начини, трябва да се спазват следните правила: модулите, съдържащи I/O операции, трябва да бъдат свързани към тестването възможно най-скоро; Критичните (т.е. най-важните) модули за програмата като цяло също трябва да бъдат тествани първо. 12
Основните предимства на тестването отгоре надолу: Вече на ранен етап от тестването е възможно да се получи работеща версия на разработваната програма; Грешките, свързани с организацията на взаимодействието с потребителя, могат бързо да бъдат идентифицирани. Недостатъците на стратегията отгоре надолу ще бъдат демонстрирани с помощта на фиг.2. Да приемем, че на следващата стъпка от тестването модул H мъничето е заменено с неговия истински текст. Тогава може да бъде трудно или дори невъзможно да се конструира такъв тест на входа на модула J, който да съответства на всяка последователност от стойности на данни, дадени предварително на входа на модула H ; не винаги ще бъде възможно лесно да се оцени съответствието на стойностите на данните на входа на модул J с необходимите тестове за проверка на модул H; т. Тъй като резултатите от изпълнението на програмата на теста, изграден за тестване на модул H, не се извеждат от него, а от модул I, може да е трудно да се възстановят действителните резултати от работата на модул H. Други проблеми, които могат да възникнат при тестване отгоре надолу: има изкушение да се комбинира дизайнът отгоре надолу с тестване, което обикновено е неразумно, т.к. дизайнът е итеративен процес и е неизбежно връщане към горните нива и коригиране на взетите по-рано решения, което обезценява резултатите от вече извършеното тестване; Може да искате да преминете към тестване на модул от следващото ниво, преди да завършите тестването на предишния по обективни причини (необходимостта от създаване на няколко версии на мъничета, използването на ресурси от модули от най-високо ниво на модули от по-ниско ниво). При тестване отдолу нагоре проверката на програмата започва с терминални модули (т.е. тези, които не извикват никакви други програмни модули). Тази стратегия в много отношения е противоположна на тестването отгоре надолу (по-специално предимствата стават недостатъци и обратно). Няма проблем с избора на следващия плъгин - единственото, което има значение, е той да извиква само вече тествани плъгини. За разлика от мъничетата, драйверите не трябва да бъдат множество версии, така че в повечето случаи са по-лесни за разработване (освен това използването на инструменти за автоматизация и отстраняване на грешки улеснява писането на драйвери, а не на мъничета). Други предимства на тестването отдолу нагоре: тъй като няма междинни модули (тестваният модул е модулът от най-високо ниво за работната версия на програмата), няма проблеми, свързани с възможността или трудността за настройка на тестове; няма възможност за комбиниране на дизайн с тестване; няма трудности, които да предизвикват желание да се премине към тестване на следващия модул, без да се завърши тестването на предишния. Основният недостатък на тестването отдолу нагоре е, че проверката на цялата структура на разработения софтуерен пакет е възможна само на последния етаптестване. Въпреки че е невъзможно да се направи недвусмислено заключение за предимството на една или друга стратегия за поетапно тестване (необходимо е да се вземат предвид специфичните характеристики на тестваната програма), в повечето случаи тестването отдолу нагоре е по-предпочитано. На третия етап от тестването на софтуерни системи (функции за тестване) се използват предимно методите за функционално тестване.
Нека започнем прегледа на методите за проектиране на тестове във функционалното тестване с метода на еквивалентно разделяне. Защото Тъй като нашата цел е да изградим набор от тестове, който има най-голяма вероятност да открие по-голямата част от грешките в програмата, която се тества, тогава тест от този набор трябва: да намали (с повече от един) броя на другите тестове, които трябва да бъдат разработени, за да се постигне предварително поставената цел за „задоволително“ тестване; покриват значителна част от други възможни тестове. С други думи: всеки тест трябва да включва тест на най-голям брой входни условия (ограничения за входни данни), определени от външната спецификация, за да се сведе до минимум общият брой на необходимите тестове; е необходимо да се раздели обхватът на входните данни на краен брой поддомейни (които ще се наричат класове на еквивалентност), така че всеки тест, който е представител на определен клас, да може да се счита за еквивалентен на всеки друг тест от този клас (т.е. откриване на същите грешки). В общия случай използването на термина „клас на еквивалентност“ тук не е съвсем точно, т.к. избраните поддомейни могат да се пресичат. Проектирането на тестове с помощта на метода на еквивалентното разделяне се извършва на два етапа: избор на класове за еквивалентност според външната спецификация; сградамного тестове. На първия етап се прави избор от спецификацията на всяко входно условие и