Тестування з інструментами Microsoft - польовий досвід

Ця стаття створена нашими друзями, партнерами з компанії Лабораторія Касперського і описує реальний досвід використання інструментів тестування від Microsoft з рекомендаціями. Автор — інженер із тестування в Лабораторії Касперського, Ігор Щегловітов.


Привіт всім. Я працюю інженером з тестування в Лабораторії Касперського в команді, що займається розробкою серверної хмарної інфраструктури на хмарній платформі Microsoft Azure.

Команда складається з розробників і тестувальників (приблизно в співвідношенні 1 до 3). Розробники пишуть код на C# і практикують TDD і DDD, завдяки цьому код виходить придатним для тестування і слабосвязанным. Тести, які пишуть розробники, запускаються або вручну з Visual Studio, або автоматично при складанні білду на TFS. Для запуску білду у нас встановлений тригер Gated Check-In, таким чином він запускається при чекине в Source Control. Особливістю даного тригера, якщо з якихось причин (чи то помилка компіляції або тести не пройшли) білд падає, то сам чекін, який запустив білд не потрапляє в SourceControl.
Ви, напевно, стикалися з твердженням, що код протестувати складно? Деякі вдаються до парного програмування. В інших компаніях спеціально виділені відділи тестування. У нас же це обов'язкове код-рев'ю і автоматизоване інтеграційне тестування. На відміну від модульних — інтеграційні тести розробляються спеціально виділеними інженерами з тестування, до яких належу і я.

Клієнти взаємодіють з нами через віддалене SOAP і REST API. Самі сервіси засновані на WCF, MVC, а дані зберігаються у Azure Storage. Для надійності і масштабування тривалих бізнес-процесів використовуються Azure Service Bus і Azure Cloud Queue.

Трохи лірики: є думка, що тестувальник — це певна щабель, щоб стати розробником. Це не зовсім так. Грань між програмістами, інженерами з тестування з кожним роком зникає. Тестувальники повинні володіти великим технічним бекграундом. Але в той же час мати дещо інше мислення, ніж розробники. Тестувальники повинні бути націлені на руйнування в першу чергу, розробники ж на створення. Разом вони повинні намагатися зробити якісний продукт.

Інтеграційні тести, також як і основний код, розробляються на C#. Імітуючи дії кінцевого споживача, вони перевіряють бізнес процеси на сконфігурованих і запущених сервісах. Для написання цих тестів використовується Visual Studio і фреймворк MsTest. Розробники використовують те ж саме. В процесі тестувальники і розробники виробляють взаиморевью коду, завдяки чому члени команди можуть завжди говорити на одній мові.

Тестові сценарії (тест-кейси) живуть і управляються через MTM (Microsoft Test Manager). Тест кейс в даному випадку — така ж сутність TFS, як баг або таск. Тест-кейси бувають ручними або автоматичними. У зв'язку зі специфікою нашої системи, ми використовуємо лише другі.

Автоматичні тест кейси зв'язуються з повного CLR найменуванню з тестовими методами (один кейс — один тестовий метод). До моменту появи MTM (Visual Studio 2010) я запускав тести як модульні, обмежуючись студією. Було складно будувати звіти по тестуванню, управляти тестами. Тепер це робиться безпосередньо через MTM.

З'явилася можливість об'єднувати тест кейси плани тестування, а всередині планів будувати плоскі та ієрархічні угруповання через TestSuite.

У нас Feature Branch розробка, тобто великі доопрацювання робляться в окремих гілках, стабілізаційних і релізних. Під кожну гілку у нас створено тест план (щоб уникнути хаосу). Після завершення стабілізації в Feature Branch гілці, в основну гілку переноситься код, а тести переносяться у відповідний їй тест план. Тест-кейси дуже легко додавати в тест-плани (Ctrl+C Ctrl+V, або через TFS query).

Трохи рекомендацій. Особисто я намагаюся для кожної гілки розділяти стабільні тести від нових. Це легко робити через TestSuite. Особливість тут у тому, що стабільні (або регресійні) тести повинні проходити на 100%. Якщо у вас не так, то варто задуматися. Ну, а після того, як новий функціонал стає стабільним, то відповідні йому тести просто переносяться в регресійний Test Suite.

Особисто для мене одним із самих нудних і рутинних процесів було створення тест-кейсів. Процес розробки автотестів у всіх різний. Хтось на початку пише докладні тестові сценарії, а потім на основі створює авто тести. У мене навпаки. Я пишу в коді (в тестовому класі) тести-пустушки (без логіки). Потім вже йде реалізації логіки, архітектури компонент тестування, тестових даних і так далі.

Після того як тести створені, їх треба перенести в TFS. Одна справа, коли тестів штук 10, а якщо 50 або 100, доведеться витратити купу часу на рутинне заповнення кроків, зв'язування кожного нового тест-кейсу з тестовим методом.

Для спрощення цього процесу Microsoft придумав утиліту tcm.exe, яка вміє автоматично, створювати тестові сценарії в TFS і включати в план тестування. Дана утиліта має ряд недоліків, один тест план чому можна додати тести з різних збірок або для тест-кейсу можна задати кроки і нормальне назву. Крім того, сама утиліта з'явилася порівняно недавно. Коли її ще не було — ми створили самописную утиліту яка автоматизує процес створення тестових сценаріїв. Також розроблені спеціальні кастомні атрибути TestCaseName і TestCaseStep, для завдання імені і кроків тестового сценарію.

Сама утиліта може як оновлювати, так і створювати тестові сценарії, включати в потрібний план. Утиліта може працювати в режимі silent, її запуск включений в Worfklow TFS білду. Таким чином вона запускається автоматично сама і додає або оновлює існуючі тестові сценарії. В результаті ми маємо актуальний тест-план.
Статус прогону тестів тест-плані (що еквівалентно якості коду) видно в спеціальних звітах. В TFS є набір шаблонів готових звітів, які на основі даних OLAP кубів будують діаграми по статусах тест кейсів і тест планів. Але у нас звіт самописний і спрощений. Ми зробили його таким, щоб кожен, хто на нього б не подивився, відразу все зрозумів.

Ось приклад:


Особливістю звіту є те, що він будується не на основі кубів, які перебудовуються не синхронно і можуть містити ще не актуальні дані, наш звіт використовує дані, які підтягуються безпосередньо через МТМ API. Таким чином ми в будь-який момент часу отримуємо актуальний статус плану тестування.
Звіт будується в HTML-форматі і розсилається на всю команду через SmtpClient. Робиться це все за допомогою простої утиліти, запуск якої включений прямо в Workflow білду: завантажити утиліту.

Крім управління тестовими сценаріями, МТМ використовується і для управління окружениями тестування і налаштуванням агентів, які запускають тести. Щоб прискорити виконання тестів (тут йдеться про тести, що перевіряють тривалі асинхронні бізнес процеси) ми використовуємо 6 агентів тестування, тобто за рахунок горизонтального масштабування агентів у нас досягається паралельність виконання тестів.

Самі по собі інтеграційні авто тести можна вручну запускати через MTM, так і через Visual Studio. Але ручний запуск відбувається під час налагодження (або тестів, або коду). У нас в команді майже на кожен баг заводиться відтворює тест. Далі баг разом з тестом передається в розробку. І розробникам простіше змоделювати проблемну ситуацію і виправити її.

Тепер про процесі регресу.

У нашому проекті є спеціальний білд, який ініціює повний прогін тестів, він запускається за тригеру як Rolling Build. Тобто, якщо пройшов успішно швидкий Gated Checkin білд, то запускається Rolling Build. Особливість даного білду — в один момент часу збирається максимум один білд.

Початок даного білду таке ж, як і в попереднього — збір останніх версій тестового основного проекту, і далі слід прогін модульних тестів.

Якщо все пройшло успішно, то запускаються спеціально написані Power Shell скрипти, які деплоят пакет зібраних сервісів в Azure. Для управлінням деплоем використовується REST API Azure. Сам деплой здійснюється на проміжне розгортання хмарної служби. Якщо деплой пройшов успішно і роль запускається без помилок, то стартую скрипти перевірки конфігурації. Якщо все добре, то відбувається перемикання ролей (проміжне розгортання стає основним) і запускаються самі інтеграційні тести.
Після прогону тестів на всю команду розсилається лист, який містить звіт про статус виконання тестів.

Перш ніж писати тести, класичні модульні, так і інтеграційні я рекомендую ознайомитися з книгами The Art of Unit Testing і xUnit Test Patterns: Refactoring Test Code
Ці книги (особисто я люблю першу), містять велику кількість порад і прийомів, як треба і не треба писати тести на будь-якому xUnit фреймворку.

Я б хотів закінчити свою статтю перерахуванням основних принципів написання коду авто-тестів у нашій команді:

  • «Ясна» CLR ім'я тестового методу. Тут основна ідея полягає в тому, що подивившись на одну назву тесту, програміст може зрозуміти, що він перевірять, з даними, що очікується. Ім'я тесту повинно складатися з 3х частин, розділених нижнім підкресленням, і виглядати приблизно так: FunctionalUnderTest_Conditions_Expectedresult
  • Сувора структура тесту — Arrange-Act-Assert. Підготовка даних, якесь дію і перевірка. Сенс такий, що тести повинні мати максимально просту і компактну структуру, по суті складається з 3х описаних раніше кроків. Завдяки цьому, досягається хороша читабельність, а також простота підтримки та налагодження тестів.
  • Тести не повинні містити умовної логіки і циклів. Тут без коментарів, якби у нас були такі тести, то довелося б писати тести тести.
  • Один тест — одна перевірка. Часто люди вставляють в свої тести купу Assert's, а потім не можуть зрозуміти, на якому саме з них тест впав. Намагайтеся робити в тесті одну перевірку, це дуже спрощує налагодження та пошук проблем. Тут трохи додам, що в деяких випадках, після однієї дії, потрібно перевірити стан кількох об'єктів, причому стан кожного з них характеризується безліччю властивостей. У такому випадку доцільно зробити два тіста, а перевірки всіх властивостей винести в окремі методи хелпери з нормальним іменем, так щоб замість Assert.IsTrue викликати ваш перевизначено ассерт. Ще, під час написання перевірок на властивості, намагайтеся писати читабельні повідомлення помилки. Тут я просто навів приклад. Насправді існує безліч різних шаблонів.
  • Тести, навіть інтеграційні, повинні бути швидкими. Намагайтеся писати їх з урахуванням цього. Я бачив безліч прикладів тестів ось з такими вставками: Thread.Sleep(60000). Уникайте цього. Якщо ви очікуєте виконання якогось асинхронного дії, то прикиньте, як можна відстежити його виконання (наприклад, асинхронний процес змінює стан базі і тп). Чи може варто розбити тест на кілька?
  • Можливо ви це не робите, але дотримуйтесь потокобезопасность в тестах. Т. к. в подальшому ви швидше за все прийдете до того, що захочете прискорити виконання тестів і чи не одним із способів досягнення цього прискорення виявиться багатопоточність.
  • Незалежність. Тести не повинні залежати від порядку їх виконання, так і один від одного. Пишіть тести з урахуванням цього принципу. Намагайтеся робити очищення тестових даних, так як часто вони призводять до різних непередбачуваних наслідки і уповільнюють виконання тестів.
Ну і наостанок хочу додати, що правильні тести дійсно роблять розробку швидкої, а код якісним.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.