Unit тестване на конзолни приложения

Като част от QA академията на Телерик, наскоро ми се наложи да пиша unit тестове за едно конзолно приложение, а именно една игра. В близко бъдеще се надявам да ми остане малко повече време, за да ви представя урок как да си създадем лесно, бързо и приятно някаква old school готина игричка, но засега, да караме направо.
Ще ви споделя накратко как да подкарате компонентни тестове, които симулативно да обработват изкарване / вкарване на информация от конзолата.

Unit testing image

Какво ще тестваме?

Няма да влизам в детайли относно същността и имплементацията на възложената задача. Ще дам конкретен пример за един метод от нея. В играта имаше изискване да има табло(таблица) с резултати или т. нар. scoreboard, който да пази имената на играчите и техния резултат. Също така, scoreboard-а трябва да изкарва играчите подредени във възходящ ред по резултата (в контекста на играта, това са брой опити за решаване на проблема, т. е. по-малкият брой опити е по-добър резултат). Ако двама играчи са с еднакъв резултат, то тогава да ги подрежда по имена (азбучен ред или още лексикално сортиране). Максималният брой играчи за показване е 5, а ако таблото е празно, се изкарва определено съобщение.

За целта използвах една много полезна структура от данни, а именно OrderedMultiDictionary. За нея, авторите й и повече информация относно другите многофункционални и интересни класове, които идват с безплатното assembly, посетете тази страница.

Ще пишем на C#. Работим с Microsoft Visual Studio 2010 Ultimate и
Team Test Framework
-а към него.

Може да видите кода на моята имплементациятук
или като картинка Test code snippet oneвляво.
Това е самият метод.

Компонентно тестване на нещо, което пише по конзолата

В същността на проблема стои въпроса как най-лесно да сравним отпечатаното на конзолата с това, което очакваме и сме посочили като expected value за нашия тест. За целта ще ни е нужно да пренасочим нанякъде стандартното печатане на конзолата. Това може да се направи лесно като използваме класа StringWriter дефиниран в namespace-а System.IO (за повече информация – MSDN).

Създаване на теста в стъпки

  1. Записваме някаква sample data в нашата структура. За целта използвам самостоятелно написан метод, който добавя в речника няколко играчи.
    Може да се направи и чрез стандартно викане на метода Add на класа OrderedMultiDictionary, който ще иска да му бъде подаден като параметър обект от тип KeyValuePair<int, Competitor>.
  2. Създаваме инстанция на класа StringWriter, например:
    StringWriter sw = new StringWriter();
  3. Използваме статичния метод на конзолата Console.SetOut(TextWriter newOut) и като параметър подаваме създадената от нас инстанция на класа StringWriter, а именно sw.
  4. Викаме метода, който ще тестваме и който стандартно пише по конзолата.
    В моя случай, това е споменатия вече по-горе статичен PrintScoreBoard(). Вече пренасочен, изходът ще се запише в обекта sw.
  5. Създаваме си променлива от тип string, която да съдържа в себе си очаквания от нас резултат.
    Важно е да се отбележи, че навсякъде, където очакваме нов ред, трябва да добавим към нашия низ литерал за нов ред. В примерчетата отдолу съм го направил използвайки placeholder и property-то NewLine на класа Environment, който универсално работи за всяка среда, под която се компилира приложението, добавяйки правилния литерал.
  6. Използваме Assert.AreEqual, сравнявайки обекта sw обърнат до string със създадената от нас променлива.
  7. Пускаме теста и ако всичко е наред, трябва да е минал успешно.

Test results image

Може да видите кода на моята имплементациятук
или като картинка вляво.Test code snippet two
Това са два теста на метода PrintScoreBoard().

 

 

 

 

Ами ако желаем да симулираме вкарване на информация от конзолата?

Това вече е малко по-абстрактно, но не толкова сложно. Използва се друг клас – StringReader (MSDN). Накратко казано, изходът отново се пренасочва към StringWriter, а входът към инстанция на StringReader.
Ще ви дам конкретен, лесен пример.

Snippet one imageSnippet two image
Това е написаният от нас метод и теста към него (двете картинки отгоре).

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

  1. Пренасочваме стандартния изход на конзолата към обект от тип StringWriter.
  2. Създаваме инстанция на класа StringReader и като параметър подаваме всичко, което очакваме от потребителя. В нашия случай, това е име последвано от нов ред (тъй като стандартно се вика Console.ReadLine()).
  3. Пренасочваме входа на конзолата към нашия обект от тип StringReader.
  4. Създваме си променлива от тип string, в която вписваме очаквания резултат. Важно е да се отбележи, че това ще е само изходната информация. Прочитането вече е извършено и ние очакваме резултат на базата на него.
    Внимавайте също и с местата, на които се очаква да бъде отпечатан нов ред.
    Често това води до грешки и пропадане на теста.
  5. Сравняваме очакваното с обекта от тип StringWriter обърнат до string.

Ако всичко е наред, тестът минава успешно.

Писането на компонентни тестове е важно за осигуряване качеството на нашата разработка без значение дали тя е desktop, web или просто конзолно приложение. Надявам се този урок да е в помощ на онези от вас, които са се сблъскали със задачата да изтестват метод, който стандартно изкарва нещо на конзолата или пък чете от нея. Желая ви успех! : )

Харесва ли ви това? Споделете:

One thought on “Unit тестване на конзолни приложения

  1. Супер обяснение! Симулацията на вкарване информация от конзолата беше това, което ми убягваше.

Leave a Reply

Your email address will not be published. Required fields are marked *