Тестване на итеративен код с помощта на mocks - има ли смисъл, как?

Искам да тествам алгоритъм, използвайки фалшиви. Алгоритъмът - в текущата реализация - итерира над клас контейнер в множество преминавания и set()s и get()s стойности от него. Целта на теста е да провери крайния резултат, записан в контейнера. Крайната стойност зависи от стойностите, прочетени и записани между преминаванията. напр. стойността на всеки елемент може да се променя многократно, докато алгоритъмът приключи и най-вероятно стойността му като резултат от итерация n ще зависи от стойността му след итерация n-1.

Харесва ми идеята за подигравки и бих искал да ги използвам в описания по-горе сценарий, тъй като това ще ми позволи да проверя грешното поведение на алгоритъма, след като то се появи, а не само когато изчислението приключи. Не съм сигурен обаче дали това всъщност би било добра идея, защото тогава ще трябва да свържа очакванията за макета наистина близо до текущата реализация (напр. „очаквайте get(element n) и върнете x, след това set( елемент n, стойност x+1), друго get(n) и връщане на x+1, след това очаквайте set(n, x+2) и т.н.").

Въпреки че ми позволява да проверя дали междинните стойности са според очакванията, мисля, че подобни очаквания биха противоречали на целта на теста (проверете дали алгоритъмът изчислява правилната крайна стойност) и вероятно тестът ще се провали, ако внедряването се промени, независимо от коректността на крайната стойност.

Сега въпросът ми: пропускам ли нещо? Има ли все пак добър начин да се използват подигравки в този сценарий? или просто няма смисъл да ги използвам тук? Как другите се справят с този проблем?

Последна забележка: Говоря за тестване на c++ код и използване на googlemock, ако това има значение за вашия отговор.

p.s.: Проверих google и статии тук (особено подигравателно итеративно поведение - справя се само с проблема с увеличаване на възвръщаемостта стойност), обаче не намерих нищо близко до моя проблем.


person jo.tr    schedule 12.09.2011    source източник


Отговори (3)


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

В противен случай използването на макет е загуба на време. Бихте ли използвали макетна версия на std::vector? Аз не бих; би било глупаво.

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

person Zan Lynx    schedule 12.09.2011
comment
Подиграването или не подиграването на std::vector всъщност е добър пример. Въпреки че, както по-горе (@Justin), мисля, че може да бъде полезно за проверка на всяка стъпка от алгоритъма, ако нещо се обърка, може да е повече работа да се уточни такъв макет, отколкото просто да преминете през кода с грешки. Така че предполагам, че си прав поне в повечето случаи. :) И за публично видими данни/методи, това мисля, че също е вярно. Потребителите на алгоритъма не се интересуват как се изчислява неговата върната стойност, те просто искат да е правилна. Благодаря, че изразихте мислите си. - person jo.tr; 13.09.2011

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

Що се отнася до тестването на отделните стъпки в кода на алгоритъма, това е по-скоро работа за преминаване с дебъгер -- не за автоматизирани тестове. Преминаването през вътрешната работа на алгоритъма трябва да е еднократно нещо и след като го направите правилно, няма нужда да продължавате да тествате отделни стъпки в него.

person Justin ᚅᚔᚈᚄᚒᚔ    schedule 12.09.2011
comment
До голяма степен съм съгласен с теб. Въпреки това, след като прочетох всички отговори, все още смятам, че би било добре да проверите/тествате отделни стъпки на алгоритъма. И все пак това вероятно не трябва да е част от всекидневното тестване, а по-скоро нещо, което човек би задействал, след като тестът започне да се проваля. От друга страна, може би все още сте прав за преминаването, тъй като кодът на алгоритъма вече документира какво трябва да прави (също като макет за проверка на единични стъпки) и шансът макетът да прилича предимно на оригиналния код е голям? - person jo.tr; 13.09.2011
comment
На практика не би трябвало да има разлика, ако тествате вътрешната работа на алгоритъма, но само провеждането на тестове, когато изходният ви тест е неуспешен, е по същество определението за „отстраняване на грешки“ (и в този момент ще бъдете практически с него така или иначе). Единичното тестване е страхотно, но изглежда, че искате да тествате само заради самото тестване – което не е непременно най-доброто използване на времето ви. Изградете своя изходен тест, подигравайте се на колкото се може повече входове, за които се сетите, и кодирайте, докато алгоритъмът даде правилния изход за всички входове. - person Justin ᚅᚔᚈᚄᚒᚔ; 13.09.2011

Единичните тестове биха били по-приложими за по-малките части, които съставят алгоритъма.

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

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

person Tom Kerr    schedule 12.09.2011
comment
Не съм сигурен, че ви разбирам правилно: бихте написали тестове с мутирал вход, за да проверите изхода и след това да ги деактивирате за ежедневни изпълнения? Това не противоречи ли на една от целите на тестването - да се провери дали изпълнението все още се държи според очакванията за всеки вход? Или твоята гледна точка е нещо различно? - person jo.tr; 13.09.2011
comment
@jo.tr Единичните тестове трябва да са бързи, всички трябва да завършват за секунди. Интеграционните тестове като този, където те тестват широк набор от детайли, могат да бъдат наистина дълги. Подобни неща са ми отнемали 10 минути, за да завърша, и това просто не е страхотно. - person Tom Kerr; 13.09.2011
comment
Добре, да, съгласен съм. Такъв вид тестове не трябва да бъдат част от тестове на единици. Мислех, че говорим за общо взето бързи тестове, които основно се изпълняват многократно с различни набори от входни данни. - person jo.tr; 19.09.2011