- PVSM.RU - https://www.pvsm.ru -
Привет.
Я думаю, многие из вас слышали про такую штуку, как FitNesse [1]. Это одна из технологий тестирования, где тесты создаются как wiki-разметка (т.е. каждый тест — это web страница), и потом запускаются на определенной технологии (Java, .Net, PowerShell и пр.) [2]
В этой статье я расскажу про пример использования FitNesse [1] для тестирования .Net приложения. И заодно покажу несколько приемов и трюков, чтобы сократить Ваше время разработки. Кстати, все эти технологии абсолютно бесплатны.
Как я сказал, все тесты в FitNesee выглядят как web-страницы. Весь тест можно представить как последовательность таблиц, причем каждая таблица содержит одну функцию. Но это теория, а на практике вызов функции выглядит так:
| login as | Some User |
Сразу поясню, что хабровские таблички выглядят растянутыми. На деле FitNesse будет их сжимать до минимального размера — см. тут: http://fitnesse.org/FitNesse.UserGuide.TwoMinuteExample [3].
В этой табличке содержится вызов метода «loginAs», который получает на вход «Some User». То есть программист реализует функцию loginAs, и далее тестировщик может её использовать. Как Вы уже поняли, имя функции — это объединенный полужирный текст. Параметры — это обычный текст. Каждая ячейка содержит только один параметр. Также каждая ячейка содержит либо полужирный текст, либо обычный.
| login history of user | Some User | is |
| When | IP | |
| 05.07.2014 | 192.168.0.1 | |
| 06.07.2014 | 192.168.0.1 |
В этом случае запускается уже функция LoginHistoryOfUserIs с аргументом Some User. На выходе ожидается коллекция объектов, каждый из которых имеет свойства When и IP.
Абсолютно аналогично можно подавать на вход набор объектов (например, настройки — эта табличка с парами ключ/значение).
Итого, каждый тест — это последовательность подобных таблиц. Программист создает функции, тестировщик создает с их помощью тестовый сценарий. Естественно, общие куски кода можно выделять в отдельные файлы, поддерживаются шаблоны, можно определить блоки, которые будут запускаться перед каждым тестом и т. д. Базовый функционал достаточно богатый для того, чтобы тестировать приложения (по крайней мере, бизнес логику, отдельно от UI)
Как я сказал выше, FitNesse может запускать функции на разных технологиях и языках программирования. Выглядит это следующим образом:
В этой статье я буду описывать про работу на .Net платформе, поэтому все классы и функции будут из этого мира. Для того, чтобы определить Runner следует написать, во-первых, эти строчки:
!define COMMAND_PATTERN {%m %p}
!define TEST_RUNNER {..binarycurrentBuildNetRunner.Executable.exe}
!path ..binarytestBuildNetRunner.InternalTests.dll
Первая относится к Runner'у (в примере используется этот Runner [4]). Она определяет, как FitNesse будет запускать Runner. На вход передаются все эти аргументы + системные переменные, но это уже детали.
Вторая строчка — это путь к Runner'у.
Третья строчка — это путь к dll'кам (их может быть несколько!), которые содержат ваше API. Всё просто.
А вот пример для другого Runner'а [5]:
!define TEST_RUNNER {${working_directory}LibfitsharpRunner.exe}
!define COMMAND_PATTERN {%m -a ${working_directory}MyTests.dll.config -r fitnesse.fitserver.FitServer,${working_directory}Libfitsharpfit.dll -v %p}
!path ${working_directory}MyTests.dll
Как Вы видите, здесь я уже определил изначально переменную ${working_directory}. И дальше, в зависимости он её значений, будут запускаться Runner'ы из разных папок и, что самое важное, тесты находятся тоже в разных папках. Такая структура очень полезна на build платформе, где зачастую может быть несколько веток, для которых идут сборки и работают тесты.
Итак, чтобы заработала вся эта система:
1. Скачиваете и запускаете FitNesse
2. Скачиваете один из Runner'ов
3. Создаете свою библиотеку, которая ссылается на библиотеки Runner'а и реализует минимальный API
4. Создаете тест, который вызывает функции вашей библиотеки
5. Запускаете его
Всё, после этого у Вас уже есть небольшой тест, который делает хоть что-то. Дальше дело за малым — улучшать качество API, увеличивать количество тестов и запускать их в процессе сборки.
Как Вы видите выше, создавать тесты, использующие API, крайне просто: Вы просто вызываете функции, сравниваете значения, создаете бизнес-сценарий. Естественно, что для этого необходимо качественно создавать функции для запуска, чтобы происходила «эмуляция» бизнес-действий. Ведь по сути, интеграционный тест — это обыкновенный тестировщик, который работает 24/7 и умеет очень быстро кликать мышкой.
А вот с созданием тестового API есть свои сложности. В своих примерах я буду использовать этот Runner [6], так как он наиболее распространенный (о нем есть упоминание даже на сайте FitNesse).
Для начала следует понять, как работает этот самый fitSharp. А делает он следующие вещи:
Вам же требуется создать классы, которые содержат эти самые функции для запуска. Для этого:
Если не было никаких недоработок, то тест запустится. Итак, что же мы сделали:
С простыми текстами более-менее понятно. Перейдем к сложным.
Рассмотрим функцию LoginAs(string userLogin). Более-менее ясно, что она должна делать по смыслу — она должна входить в некую систему, а дальше тестовая среда должна работать как бы от этого пользователя. Всё логично. Однако какой же параметр передать на вход? Вариант 1 — передать просто строчку, а потом уже разбирать её. Не очень удобно, так как если у нас есть две функции: login и Get Login History, то придется повторить процедуру парсинга и пр.
Хоть это и не документировано, но на деле есть очень просто решение: если Вы хотите принимать на вход класс, то у него должен быть публичный статический метод Parse(string arg). Который, естественно, вернет наш класс. Например, Int32 полностью подходит под определение (для структур это тоже работает). Пользуясь этой схемой, получаем неплохое разделение ответственности: наши тестовые методы будут работать с уже более-менее обработанными данными. И все исключения при разборе всё равно отобразятся пользователю.
Абсолютная аналогия происходит с методами, которые возвращают коллекции (см. выше). Они проверяются с помощью таблички, ну то есть тестировщик подает на вход ожидаемые данные, а Ваша функция должна вернуть правильную коллекцию. В этом случае, если Вы возвращаете класс, в котором все поля могут быть разобраны (ну т. е. все типы имеют метод Parse), то будет происходить не сравнение строк, а сравнение объектов. Которое уже полностью контролируется Вами.
Зачастую удобно добавлять в систему данные с помощью таблиц. Стандартный пример — это любой Mapping (например, настройки — это Map: name --> value). То есть по сути на вход передается таблица и нескольких колонок. Это тоже можно сделать в fitSharp. Для этого Вам потребуется создать такой метод:
public SetUpFixture SetSettingsForUserAs(User user). Название метода и аргументы могут быть любыми, а вот возвращаемое значение — именно SetUpFixture.
Далее реализуем класс —
internal sealed class MySettings : SetUpFixture
{
private readonly User user;
public MySettings(User user)
{
this.user = user;
}
public NameValue(string parameterName, string parameterValue)
{
}
}
И в итоге наша таблица будет выглядеть так:
| Set Settings For User | habrauser | As |
| Name | Value | |
| First Name | John | |
| Last Name | Doe |
Как произошел mapping колонок более-менее ясно. И аргументы теперь подаются в виде вот таких табличек.
Итак, Вы создали тест. Или даже набор тестов — Test Suite. И они заработали в FitNesse. Теперь самое время начать запускать их автоматически.
Есть два основных способа для запуска:
http://myServer:8080/MyTests?suite&format=xml
). Результатом будет xml файл с информацией, что выполнялось, как отработало, время, результат и пр.
Второй способ работает всегда, то есть не требуется запущенного FitNesse, более того, можно держать работающий FitNesse и одновременно с этим выполнять тесты таким способом. Все результаты будут появляться в обоих FitNesse'ах.
Как итог, в этой статье я постарался быстро-быстро пробежаться по верхам и рассказать, как создать и запускать интеграционные тесты FitNesse. Чаще всего через эти шаги проходят методом проб и ошибок, однако если бы у меня год назад была бы эта статья, она бы сэкономила пару дней точно. Надеюсь, она поможет и вам.
Автор: imanushin
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/testirovanie/64295
Ссылки в тексте:
[1] FitNesse: http://fitnesse.org/
[2] (Java, .Net, PowerShell и пр.): http://fitnesse.org/PlugIns
[3] http://fitnesse.org/FitNesse.UserGuide.TwoMinuteExample: http://fitnesse.org/FitNesse.UserGuide.TwoMinuteExample
[4] в примере используется этот Runner: https://github.com/imanushin/NetRunner
[5] другого Runner'а: https://github.com/jediwhale/fitsharp/downloads
[6] этот Runner: https://github.com/jediwhale/fitsharp
[7] Application Domain: http://msdn.microsoft.com/ru-ru/library/system.appdomain(v=vs.110).aspx
[8] этот NuGet пакет: https://www.nuget.org/packages/FitSharp/
[9] Источник: http://habrahabr.ru/post/228967/
Нажмите здесь для печати.