MVC 5 Единични тестове срещу интеграционни тестове

В момента работя по проект MVC 5, използвайки Entity Framework 5 (може скоро да премина към 6). Първо използвам база данни и MySQL със съществуваща база данни (с около 40 таблици). Този проект започна като „доказателство за концепцията“ и сега моята компания реши да използва софтуера, който разработвам. Затруднявам се с тестовата част.

Първата ми идея беше да използвам предимно интеграционни тестове. По този начин почувствах, че мога да тествам кода си, а също и основната си база данни. Създадох скрипт, който изхвърля съществуващата схема на база данни в „тестова база данни“ в MySQL. Винаги започвам тестовете си с чиста база данни без данни и създавам/изтривам малко данни за всеки тест. Работата е там, че отнема доста време, когато изпълнявам тестовете си (пускам тестовете си много често).

Мисля да заменя интеграционните си тестове с модулни тестове, за да ускоря времето, необходимо за изпълнението им. Бих „премахнал“ тестовата база данни и вместо това бих използвал само подигравки. Тествах няколко метода и изглежда, че работи чудесно, но се чудя:

  1. Смятате ли, че подигравката с моята база данни може да „скрие“ грешки, които могат да възникнат само когато кодът ми се изпълнява срещу реална база данни? Обърнете внимание, че не искам да тествам Entity Framework (сигурен съм, че добрите хора от Microsoft са свършили страхотна работа с това), но може ли кодът ми да работи добре срещу подигравки и прекъсвания срещу MySQL?
  2. Смятате ли, че преминаването от интеграционно тестване към тестване на единици е крал на „понижаване“?
  3. Смятате ли, че премахването на интеграционното тестване и приемането на модулно тестване за разглеждане на скоростта е добре.
  4. Наясно съм, че съществува някаква рамка, която изпълнява тестовете срещу база данни в паметта (т.е. рамка Effort), но не виждам предимствата на това спрямо подигравката, какво пропускам?

Наясно съм, че този тип въпроси са склонни към отговори от типа „зависи от вашите нужди“, но съм сигурен, че някои може да са минали през това и могат да споделят знанията си. Също така съм наясно, че в един перфектен свят бих направил и двете (тестове с помощта на фалшиви и с база данни), но нямам толкова време.

Като страничен въпрос какъв инструмент бихте препоръчали за подигравка. Казаха ми, че „moq“ е добра рамка, но е малко бавна. Какво мислиш?


person Pierre    schedule 01.07.2015    source източник
comment
Единичните тестове са за тестване на кода, който вие сте написали, интеграционните тестове са за тестване на взаимодействие с неща, които други са написали. Не трябва да премахвате интеграционните тестове, но те не трябва да бъдат тестовете, които изпълнявате на всеки 10 минути.   -  person Claies    schedule 02.07.2015
comment
като правило доброто разделяне на проблемите и инжектирането на зависимости ще ви позволи да тествате почти всяка функция във вашето приложение, сякаш е цялото приложение само по себе си. Ако вашата функция разчита на резултата от друга функция/услуга/библиотека, за да даде правилен отговор, тогава тя най-вероятно не е преработена достатъчно.   -  person Claies    schedule 02.07.2015


Отговори (1)


  1. Смятате ли, че подигравката с моята база данни може да „скрие“ грешки, които могат да възникнат само когато кодът ми се изпълнява срещу реална база данни? Обърнете внимание, че не искам да тествам Entity Framework (сигурен съм, че добрите хора от Microsoft са свършили страхотна работа по въпроса), но може ли кодът ми да работи добре срещу подигравки и прекъсвания срещу MySQL?

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

  1. Смятате ли, че преминаването от интеграционно тестване към тестване на единици е крал на „понижаване“?

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

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

Добре е много субективно. Бих казал не, но не е нужно да изпълнявате всички свои тестове през цялото време. Повечето рамки за тестване (ако не всички) ви позволяват да категоризирате вашите тестове по някакъв начин. Това ви позволява да създавате подмножества от вашите тестове, така че можете например да имате категория „Интегриране на база данни“, в която да поставите всичките си тестове за интегриране на база данни, или „От край до край“ за пълни тестове от край до край. Предпочитаният от мен подход е да имам отделни компилации. Обичайната/непрекъсната компилация, която бих стартирал преди/след всяко регистриране, изпълнява само модулни тестове. Това дава бърза обратна връзка и потвърждение, че нищо не е счупено. По-рядко срещана / ежедневна / нощна компилация, в допълнение към изпълнението на модулните тестове, също би изпълнявала по-бавни / повтарящи се интеграционни тестове. Също така бих склонил да провеждам интеграционни тестове за области, върху които съм работил, преди да проверя в кода дали има възможност кодът да повлияе на интеграцията.

  1. Наясно съм, че съществува някаква рамка, която изпълнява тестовете срещу база данни в паметта (т.е. рамка Effort), но не виждам предимствата на това спрямо подигравката, какво пропускам?

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

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

Също така съм наясно, че в един перфектен свят бих направил и двете (тестове с помощта на фалшиви и с база данни), но нямам толкова време.

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

Като страничен въпрос какъв инструмент бихте препоръчали за подигравка. Казаха ми, че „moq“ е добра рамка, но е малко бавна. Какво мислиш?

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

Подигравката от всякакъв вид обикновено е доста бърза, обикновено (освен ако не използвате частични подигравки) премахвате цялата функционалност на класа/интерфейса, който подигравате, така че да работи по-бързо от нормалния ви код. Единствените проблеми с производителността, за които съм чувал, са, че ако сте MS fakes/shims, понякога (в зависимост от сложността на асемблирането, което се фалшифицира) може да отнеме известно време, за да бъдат създадени фалшивите асембли.

Двете рамки, които съм използвал и са малко по-различни, са MS fakes/shims и Typemock. Версията на MS изисква определено ниво на визуално студио, но ви позволява да генерирате фалшиви сборки с подложки на определени типове обекти, което означава, че не е нужно да предавате макетите си от вашия тест до мястото, където се използват. Typemock е комерсиално решение, което използва API за профилиране, за да инжектира код, докато вашите тестове се изпълняват, което означава, че може да достигне до части, които други подигравателни рамки не могат. И двете са особено полезни, ако имате кодова база, която не е написана с предвид тестване на модули, което може да помогне за преодоляване на празнината.

person forsvarir    schedule 02.07.2015