Часть 1. Введение
Часть 2. База (эта статья)
Часть 3. Интересные возможности
Часть 4. Демо FitNesse + Jenkins
Часть 5. Пример трансформации PowerShell скрипта в тест
Плагин для sublime, который подсвечивает синтаксис теста на Fitnesse+PowerSlim
Надеюсь, что вы нашли время (или желание?) посмотреть примеры, которые можно найти в пакете PowerSlim. Если вы их не видели, ничего страшного: все равно с нуля там ничего не понятно. Ну или почти ничего (да, Костя?) :)
Давайте попробуем разобраться, как использовать PowerSlim с пользой. Но тут нам придется углубиться чуток в теорию и разбираться на примерах.
Начнем, пожалуй, с организации тестов.
В Fitnesse есть три типа страниц: статические, сюиты и тестовые. Статические служат просто для размещения нужной информации и, например, страницы с набором ссылок с описанием фичей запланированных на релиз или примеров использования API библиотеки:
Страницы-сюиты.
Позволяют запустить тесты со всех тестовые страницы, расположенные под сюитой. Тесты при этом выполняются последовательно. Тесты с ошибками не останавливают выполнение сюиты. Отчет по результатам выполнения позволяет "ходить" по странице и смотреть подробности. Это вы могли видеть при первом запуске тестовой сюиты PowerSlim (см. первый пост). Кроме этого, есть возможность посмотреть историю выполнения тестов (Tools -> Test History):
Тестовые страницы вы уже видели и даже редактировали (если читали предыдущий пост).
Имена страниц должны содержать как минимум 2 заглавные буквы расположенные не рядом (не знаю как это описать понятней :) ). В любом случае Fitnesse (кстати правильнее FitNesse) не разрешит вам создать страницу с неправильным названием.
Как вы уже могли заметить, дерево веб-страниц на Fitnesse портале дублирует собой структуру папок под FitNesseRoot на файловой системе: папка - это имя страницы, внутри хранится ее контент (content.txt), история изменений (в *.zip файлах) и файл properties.xml со свойствами страницы, определяющими, например, ее тип. Поэтому при перемещении папок структура в web-view также меняется (по нажатию F5).
Редактировать страницы (content.txt) можно (и чаще даже проще) в удобном вам текстовом редакторе.
Страницы можно включать в другие страницы, подробнее об этом в следующем посте.
В Fitnesse есть переменные. Значение переменной наследуется всем страницами расположенным в иерархии под той, в которой она объявлена. На каждой странице переменная может быть переопределена и тогда уже новое значение будет наследоваться ниже по структуре.
Для чего они нужны? Самое простое применение, это задание имен стендов, где нужно запускать тесты, пути на файловой системе, URL и тп. Все то, что может быть определено и изменено в одном месте, а использоваться во многих.
Как же писать тесты? Для следованию правилу "трех А" (Arrange-Act-Assert) нам могут понадобиться такие операции:
Откройте страницу (http://localhost:8080/PowerSlim.OriginalMode.SuiteRemoting.TestQuery) из сюиты PowerSlim
Обратите внимание на влинкованные SuiteSetUp, SetUp вверху страницы и TearDown, SuiteTearDown внизу.
Если посмотреть исходники тестовой страницы (через "Edit"), то вы не увидите никаких намеков на включение дополнительных страниц. Их код автоматически подставляется движком Fitnesse в каждую тестовую страницу при ее выполнении. При этом запуск сюиты вызовет SuiteSetUp и SuiteTearDown только один раз на всю сюиту.
Эти специальные страницы предназначены для включения кода выполняющего общую настройку тестового окружения и зачистку после выполнения. Такая возможность помогает реализовывать изолированные и независимые друг от друга тесты.
Естественно, индивидуальную настройку среды выполнения теста все равно придется делать, но не следует забывать о выносе похожего кода в одно место (удаление дупликации).
Act
Код выполняемый для настройки (Arrange) и запуска (Act) использует одни и те же функции PowerSlim. Чаще всего используется eval. Много примеров в тестовой сюите PowerSlim.
Assert
Для проверки результатов используются вариации Query. Одиночный вызов Query ожидает, что результат будет содержать тот и только тот массив данных, который описан в тесте строчками под командой. Порядок возвращения по строчкам не важен. При использовании перед Query служебного слова subset проверяется наличие вхождения заданного тестом в итоговом массиве данных.
Интересный момент связан с тем, как определить, какие свойства-колонки мы должны задать тестом. Проще всего, для этого запустить тот PowerShell скрипт, который вы хотите использовать в PowerShell консоли (или ISE) с командой get-member (gm) через pipe '|'
Результатом будет являться набор свойств и методов, которыми обладает тип данных объектов, которые будут возвращены скриптом (жесть - но сейчас будет понятней)
PowerSlim возвращает только Property иNoteProperty объектов сложных типов.
Соответственно в тесте, мы будем использовать одно из этих свойств.
Если результат скрипта это массив строчек, то PowerSlim на его базе сгенерирует и вернет массив PSObject со свойствами Value и COMPUTERNAME. В Value будет положено значение строчки, а в COMPUTERNAME имя стенд-машины, на которой выполнялся запрос.
Смотри пример в PowerSlim.OriginalMode.SuiteRemoting.TestRemoting.
Похожим образом конвертируются массивы hashtable и dictionary. Подробнее можно посмотреть в тестах PowerSlim:TestArrayInQueryTable, TestArrayOfNumbers, TestGenericDictionary, TestPowerShellHashTableNotation.
Кроме проверки Query, для assert'ов может использоваться команда check, которая сравнивает значение полученное во время запуска теста с ожидаемым. При этом в качестве параметров может выступать выражение. Смотри пример в PowerSlim.OriginalMode.SuiteCommon.TestScript.
Фуххх. Не знаю как вы, а я бы утомился читать столько слов. Но надеюсь, что эта информация будет полезней и понятней, когда вы посмотрите на примеры и попытаетесь написать свои первые тесты.
Да, важно. Для того чтобы Fitnesse не воспринимал PowerShell pipe символ '|' как разделитель таблицы, весь запрос надо заключать между символов !- ... -! Если при этом внутри запроса используется переменная, то ее надо вынести из этого "забора":
Я добавил немного примеров из жизни в ExampleS. Теперь, если взять свежий PowerSlim, то там это уже будет.
Также можно обратить внимание на обсуждения (1 и 2) из первого поста, там уже advanced technics обсуждаются :) Подробней о них в следующем посте.
Удачи в изучении. Главное не пугаться :)
Продолжение
Часть 2. База (эта статья)
Часть 3. Интересные возможности
Часть 4. Демо FitNesse + Jenkins
Часть 5. Пример трансформации PowerShell скрипта в тест
Плагин для sublime, который подсвечивает синтаксис теста на Fitnesse+PowerSlim
Надеюсь, что вы нашли время (или желание?) посмотреть примеры, которые можно найти в пакете PowerSlim. Если вы их не видели, ничего страшного: все равно с нуля там ничего не понятно. Ну или почти ничего (да, Костя?) :)
Давайте попробуем разобраться, как использовать PowerSlim с пользой. Но тут нам придется углубиться чуток в теорию и разбираться на примерах.
Начнем, пожалуй, с организации тестов.
В Fitnesse есть три типа страниц: статические, сюиты и тестовые. Статические служат просто для размещения нужной информации и, например, страницы с набором ссылок с описанием фичей запланированных на релиз или примеров использования API библиотеки:
Страницы-сюиты.
Позволяют запустить тесты со всех тестовые страницы, расположенные под сюитой. Тесты при этом выполняются последовательно. Тесты с ошибками не останавливают выполнение сюиты. Отчет по результатам выполнения позволяет "ходить" по странице и смотреть подробности. Это вы могли видеть при первом запуске тестовой сюиты PowerSlim (см. первый пост). Кроме этого, есть возможность посмотреть историю выполнения тестов (Tools -> Test History):
Тестовые страницы вы уже видели и даже редактировали (если читали предыдущий пост).
Имена страниц должны содержать как минимум 2 заглавные буквы расположенные не рядом (не знаю как это описать понятней :) ). В любом случае Fitnesse (кстати правильнее FitNesse) не разрешит вам создать страницу с неправильным названием.
Как вы уже могли заметить, дерево веб-страниц на Fitnesse портале дублирует собой структуру папок под FitNesseRoot на файловой системе: папка - это имя страницы, внутри хранится ее контент (content.txt), история изменений (в *.zip файлах) и файл properties.xml со свойствами страницы, определяющими, например, ее тип. Поэтому при перемещении папок структура в web-view также меняется (по нажатию F5).
Редактировать страницы (content.txt) можно (и чаще даже проще) в удобном вам текстовом редакторе.
Страницы можно включать в другие страницы, подробнее об этом в следующем посте.
В Fitnesse есть переменные. Значение переменной наследуется всем страницами расположенным в иерархии под той, в которой она объявлена. На каждой странице переменная может быть переопределена и тогда уже новое значение будет наследоваться ниже по структуре.
Для чего они нужны? Самое простое применение, это задание имен стендов, где нужно запускать тесты, пути на файловой системе, URL и тп. Все то, что может быть определено и изменено в одном месте, а использоваться во многих.
- настроить тест
- выполнить действие, например создать, запустить, удалить что-нибудь и тп
- проверить результат
Откройте страницу (http://localhost:8080/PowerSlim.OriginalMode.SuiteRemoting.TestQuery) из сюиты PowerSlim
Обратите внимание на влинкованные SuiteSetUp, SetUp вверху страницы и TearDown, SuiteTearDown внизу.
Если посмотреть исходники тестовой страницы (через "Edit"), то вы не увидите никаких намеков на включение дополнительных страниц. Их код автоматически подставляется движком Fitnesse в каждую тестовую страницу при ее выполнении. При этом запуск сюиты вызовет SuiteSetUp и SuiteTearDown только один раз на всю сюиту.
Эти специальные страницы предназначены для включения кода выполняющего общую настройку тестового окружения и зачистку после выполнения. Такая возможность помогает реализовывать изолированные и независимые друг от друга тесты.
Естественно, индивидуальную настройку среды выполнения теста все равно придется делать, но не следует забывать о выносе похожего кода в одно место (удаление дупликации).
Act
Код выполняемый для настройки (Arrange) и запуска (Act) использует одни и те же функции PowerSlim. Чаще всего используется eval. Много примеров в тестовой сюите PowerSlim.
Assert
Для проверки результатов используются вариации Query. Одиночный вызов Query ожидает, что результат будет содержать тот и только тот массив данных, который описан в тесте строчками под командой. Порядок возвращения по строчкам не важен. При использовании перед Query служебного слова subset проверяется наличие вхождения заданного тестом в итоговом массиве данных.
Интересный момент связан с тем, как определить, какие свойства-колонки мы должны задать тестом. Проще всего, для этого запустить тот PowerShell скрипт, который вы хотите использовать в PowerShell консоли (или ISE) с командой get-member (gm) через pipe '|'
Результатом будет являться набор свойств и методов, которыми обладает тип данных объектов, которые будут возвращены скриптом (жесть - но сейчас будет понятней)
PowerSlim возвращает только Property иNoteProperty объектов сложных типов.
Соответственно в тесте, мы будем использовать одно из этих свойств.
Если результат скрипта это массив строчек, то PowerSlim на его базе сгенерирует и вернет массив PSObject со свойствами Value и COMPUTERNAME. В Value будет положено значение строчки, а в COMPUTERNAME имя стенд-машины, на которой выполнялся запрос.
Смотри пример в PowerSlim.OriginalMode.SuiteRemoting.TestRemoting.
Похожим образом конвертируются массивы hashtable и dictionary. Подробнее можно посмотреть в тестах PowerSlim:TestArrayInQueryTable, TestArrayOfNumbers, TestGenericDictionary, TestPowerShellHashTableNotation.
Кроме проверки Query, для assert'ов может использоваться команда check, которая сравнивает значение полученное во время запуска теста с ожидаемым. При этом в качестве параметров может выступать выражение. Смотри пример в PowerSlim.OriginalMode.SuiteCommon.TestScript.
Фуххх. Не знаю как вы, а я бы утомился читать столько слов. Но надеюсь, что эта информация будет полезней и понятней, когда вы посмотрите на примеры и попытаетесь написать свои первые тесты.
Да, важно. Для того чтобы Fitnesse не воспринимал PowerShell pipe символ '|' как разделитель таблицы, весь запрос надо заключать между символов !- ... -! Если при этом внутри запроса используется переменная, то ее надо вынести из этого "забора":
Я добавил немного примеров из жизни в ExampleS. Теперь, если взять свежий PowerSlim, то там это уже будет.
Также можно обратить внимание на обсуждения (1 и 2) из первого поста, там уже advanced technics обсуждаются :) Подробней о них в следующем посте.
Удачи в изучении. Главное не пугаться :)
Продолжение
Молодец! Назначаешься главным популяризатором фитнеса в рунете. :)
ОтветитьУдалитьвас то не дождешься ;)
ОтветитьУдалитьКлассно написано! Только реально много. Предлагаю следующий коротенький пост про встроенные переменные (например PAGE_NAME) http://fitnesse.org/FitNesse.UserGuide.QuickReferenceGuide#GlobalVARIABLES.
ОтветитьУдалитьИ про check, check not и regexp нотацию =~/pattern/
ГДЕ МОЙ КОМЕНТЫ!!!
ОтветитьУдалитьне кипятись :) все будет
ОтветитьУдалитьну, ты сам напросился ;) ждем от тебя пост на эту тему.
ОтветитьУдалитьА какие предлагаются варианты переключения между лабами? Можно, конечно, вынести страничку с переменными выше сьюты, импортировать её, и когда надо поменять лабу, просто положить на место странички с переменными другую страничку (и перезапустить фитнес). Но это не кажется идеальным.
ОтветитьУдалитьКак-нибудь проще это делается?
а зачем так сложно, с подменой? просто другую страницу подключить с переменными. опять же, для чего это может понадобиться?
ОтветитьУдалитьДва случая: первый - это один человек написал тест, другой человек получил тест в архиве, из сорс-контрола и т.д. Тут отдельная страничка помогает, перезапуск фитнеса не нужен, код один - переменные разные.
ОтветитьУдалитьВторой случай - прогнал тесты на одной лабе, хочется без редактирования страниц прогнать на другой (например, одним линком - тесты в одной лабе, другим - в другой, а линк же запускается без человека).
К примеру, абсолютно одинаковые тесты и/или сьюты надо прогнать по какому-нибудь правилу на наборе лаб.
По сути - код один, переменные разные, но надо чтобы значения переменных менялись по правилу.
Таблицы тестов пишутся в страницеX (например статической). Потом эта страница включается в testpage1 и testpage2 с разными define. Это ведь работает.
ОтветитьУдалитьЯ ж так и спросил - как юзать разные значения define.
ОтветитьУдалить1) Редактировать переменные (а их может набежать несколько) неохота.
2) Редактировать инклюд на страничку с другими define - да тоже неохота.
3) Редактировать страничку как файл - неохота, потому что не знаю, как зарефрешить фитнес.
4) Можно подключить другой фитнес и делать Edit locally - но это как п. 1, неохота :)
5) Можно, конечно, сделать подгрзуку их откуда-то и это "откуда-то" подкладывать руками или скриптами.
6) Есть parametrized include, но это запуск нескольких тестов или сьют с разными параметрами, а не смена параметров. Решение обратной задачи.
7) если лаб несколько (не произвольное количество), можно создать несколько страниц с define, раздать им разные тэги, раздать эти тэги всем страницам сьюты(сьют), и тогда запускать по тэгам через линк или через SuiteQuery.
8) можно иметь несколько страниц с define, брать через rest контент страницы, класть через rest контент страницы на страницу для define, которая импортится и сохранять страницу которая импортится.
Получается, что опции 5, 7,8 более-менее интересные.
фухх, выглядит угрожающе. У меня такого заморока и его необходимости пока не было :)
ОтветитьУдалитьМаксим, а ты не думал на AutoConfeTQA (http://confetqa.ru/program-auto/) выступить с этой темой? Показать живьем, так-сказать, как за 20 минут все сделать красиво и пройти первый тест?:)
ОтветитьУдалитьответил на почту :)
ОтветитьУдалитьПросим-просим! :)
ОтветитьУдалитьВсё читаю читаю про фитнес, и никак не пойму(не найду), как мне конкретно протестировать на си шарпе написанное приложение. Есть библиотека с тестируемыми классами. Я должен для них написать еще одну библиотеку на си шарпе, которая будет предоставлять интерфейс к этим классам для фитнеса, А вот как в целом это всё запустить, не пойму, не получается. Как со стороны финтнеса писать в викиразметки тесты написано. а вот как всё это интегрировать что бы работало, не получается. Вот например после ваших статей запустил поверслим. Вроде что-то протестировал. А как это соединить с приложением не допираю ))
ОтветитьУдалитьА "приложение" - это что? Это UI, сервис, cmd-утилита? "Живет" ли весь код внутри exe-шника или он просто использует код из библиотек (dll assembly)?
ОтветитьУдалитьСтранно, написал комментарий, а он пропал. Или просто еще не прошел модерацию? Я пытаюсь для начала хотя бы библиотеку протестировать. Он игнорирует тесты почему-то. Скачал последнюю версию NSlim, всё как в туториалах сделал, а не работает :( Разные версии раннера скачивал. Не пойму как устроено взаимодействие с фитнессом, потому не могу разобраться в чем ошибка. Первый запуск проходит удачно(если отладочный режим запустить) - возвращает 0. А дальше ничего не происходит.
ОтветитьУдалитьTest System: slim:C:\nfit\Runner.exe
ОтветитьУдалитьВот так пишет:
variable defined: TEST_SYSTEM=slim
variable defined: COMMAND_PATTERN=%m -r fitSharp.Slim.Service.Runner,C:\nfit\fitsharp.dll %p
variable defined: TEST_RUNNER=C:\nfit\Runner.exe
classpath: C:\nfit\DigitalVideoRecorder.dll
variable defined: COLLAPSE_SETUP=true
variable defined: COLLAPSE_TEARDOWN=true
importDigitalVideoRecorder Test not run
Create Programs Test not runNameChannelDayOfWeekTimeOfDayDurationInMinutesid?House Test not run4 Test not runMonday Test not run19:00 Test not run60 Test not run$ID= Test not run
А почему бы не попробовать PowerSlim? К сожалению, я ничего не могу подсказать по nslim и его раннеру. А в PowerSlim вы можете дергать методы вашей библиотеки и проверять результат. Это 100% работает, ну или во всяком случае мы попробуем разобраться почему нет, если вдруг "нет" :). PS на модерации комментов не висит.
ОтветитьУдалитьПопробовал - вот что выдает. Test Pages: 0 right, 0 wrong, 1 ignored, 0 exceptions Assertions: 0 right, 0 wrong, 0 ignored, 0 exceptions (2,659 seconds)
ОтветитьУдалитьА страница с тестом такая -
!define TEST_SYSTEM {slim}
!define COMMAND_PATTERN {PowerShell -NonInteractive -ExecutionPolicy unrestricted -file .\slim.ps1}
!define HOST_VERSION {4.0 }
!path C:\nfit\DigitalVideoRecorder.dll
!define COLLAPSE_SETUP {true}
!define COLLAPSE_TEARDOWN {true}
!|import|
|DigitalVideoRecorder|
!|Create Programs |
|Name |Channel|DayOfWeek|TimeOfDay|DurationInMinutes|id? |
|House|4 |Monday |19:00 |60 |$ID=|
А ошибки такие -
slim:fitnesse.slim.SlimServiceDate:12:20:04 PM (MSK) on пятница, октября 31, 2014Test Page:.DigitalVideoRecorderCommand:PowerShell -NonInteractive -ExecutionPolicy unrestricted -file .\slim.ps1 8093Exit code:0Time elapsed:2.609 seconds
Standard Output:
True
Standard Error:
��� ".\DigitalVideoRecorder" �� �ᯮ����� ��� ��� ���������, �㭪樨, 䠩�� �
�ਯ� ��� �믮��塞�� �ணࠬ��. ����� �ࠢ��쭮��� ����ᠭ�� �����, � ⠪
�� ����稥 � �ࠢ��쭮��� ���, �� 祣� ������ ������.
��ப�:1 ����:2
+ . <<<< .\DigitalVideoRecorder
+ CategoryInfo : ObjectNotFound: (.\DigitalVideoRecorder:String)
[], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Вы пытаетесь использовать Fit вместо Slim. Для того, чтобы дернуть код библиотеки из powerslim не надо реализовывать Fixture.
ОтветитьУдалитьМожно прямо вызывать методы assembly из powershell.
Например в ExampleS.CreateProductShare, видно как делать функцию и как ее использовать.
Внутри функции можно делать явную загрузку вашей реальной библиотеки и вызывать ее методы
$Assembly = [System.Reflection.Assembly]::LoadFrom("YOUR_ASSEMBLY");
$recorder = New-Object YouLibrary.DigitalVideoRecorder$recorder.GrabVideo($whereToSave)
Тут вызывается реальный продакшен метод GrabVideo вашей библиотеки. Дальше вы можете проверить, что файл например записался, имеет правильный формат и тп.
Можете прислать свои контакты мне на почту mail.ru (maxim точка shulga), можно пообщаться ближе к "телу" кода, сценариям использования и тп.
Хорошо, сейчас переварю и попробую поиграться с тем, что вы написали, и уже более конкретно спрошу, если не разберусь.
ОтветитьУдалитьгуд. это правильный подход :)
ОтветитьУдалитьОчень здорово, теперь можно разработку начинать с написания не юнит тестов, а прям с викистранички с приемочными требованиями к функционалу, и плясать уже от них. :) Правда пока первые шаги, но уже большое удовлетворение ))) Хотя я себе немного по другому представлял, тут слишком уж получается низкоуровнево приходится тесты описывать. Не совсем пока понятно, где при таком построении тестов можно впихнуть реализацию общего языка, который должны понимать и разработчики и заказчики. В общем ещё надо поразмышлять )
ОтветитьУдалитьначну с того, что "общий язык, который должны понимать и разработчики, и заказчики" это прикольно, но в моей практике не работало. Скорее наоборот. Но само направление идеи правильное - разработчик может сделать кубиков, а, например, аналитик или тестировщик, может из этих кубиков истории складывать. Роль кубиков могут играть PowerSlim сценарии, внутри которых скрыт весь низкоуровневый код, а снаружи это могут быть просто "start vm" (и все равно каким образом она стартует) или "decode video" (а то что для этого делается LoadAssembly, создается объект класса и вызывается метод - это уже реализация, которая может меняться, стабироваться и тд). Снаружи это просто "action".
ОтветитьУдалить