Всю прошедшую неделю я потихоньку занимался развитием DelphiSpec. Хотя свободного времени у меня было не так уж и много, проделана большая работа и проект близок к той стадии, когда я без стеснения смогу объявить о выходе версии 1.0.
Давайте я вам вкратце расскажу о том, что теперь умеет DelphiSpec. Базовые вещи озвучены в предыдущем посте, обсудим, что появилось нового. А нового довольно много.
Во-первых, произошла по сути косметическая, но очень приятная модернизация — в классе содержащем step definitions простые шаги можно описывать без применения атрибутов.
В первом посте я показывал вам такой синтаксис:
// пример сценария: "Given user ROOT exists" [Given_('user (.*) exists')] procedure MyProcName(const Name: string);
Он отлично работает и сейчас, но теперь можно сделать еще проще — без атрибутов:
// пример сценария: "Given user ROOT exists" procedure Given_user_name_exists(const Name: string);
То есть можно использовать имя самого метода для описания типа и синтаксиса шага. Выбирайте как удобнее.
Также теперь поддерживаются не только строковые параметры. Такой код будет работать:
// пример сценария: "Given I have 3 apples" procedure Given_I_have_N_apples(N: Integer);
Можно передать даже массив:
// пример сценария: "Given I have a list 1,2,3,4" procedure Given_I_have_a_list_Ns(Ns: TArray<Integer>);
И даже массив записей:
type TUserInfo = record Name: string; Password: string; Id: Integer; end; // пример сценария // Given users exist: // | id | name | password | // | 1 | Roman | pass1 | // | 2 | Other | pass2 | procedure Given_users_exist(Table: TArray<TUserInfo>);
Последний пример демонстрирует интересный тип данных Gherkin — data table. Обратите внимание, что такая таблица в метод-обработчик передается как массив обычных типизированных записей.
Всю работу с типами берет на себя DelphiSpec, вам об этом думать не придется. Библиотека может это делать благодаря магии RTTI. Не верьте, когда вам говорят, что волшебства не бывает :)
Еще один тип данных, который поддерживает Gherkin и теперь реализован в DelphiSpec — это «многострочные строки» в стиле Python. Такая строка обрамляется троекратными двойными кавычками сверху и снизу, а в метод-обработчик передается как обычный string:
Given I have a blacklist: """ m@mail.com 123@mail.com """
С типами данных я, кажется, закончил. Расскажу еще о паре интересных возможностей.
Добавлена поддержка блока background. Этот блок позволяет описать контекст выполнения сценариев — он выполняется перед каждым сценарием.
Feature: Accounts Background: Given users exist: | id | name | password | | 1 | Roman | pass1 | | 2 | Other | pass2 | Scenario: Correct Login Given my name is "Roman" And my password is "pass1" When I login Then I have access to private messages Scenario: Incorrect Login Given my name is "Roman" And my password is "pass2" When I login Then access denied
Также теперь можно описывать не только отдельные сценарии, но и более общие структуры сценариев:
Scenario Outline: Add two numbers Given I have entered <num1> in calculator And I have entered <num2> in calculator When I press Add Then the result should be <sum> on the screen Examples: | num1 | num2 | sum | | 1 | 2 | 3 | | 4 | 5 | 9 | | 3 | 1 | 4 |
Такая структура будет развернута в несколько сценариев — по одному на каждую строку таблицы. В дереве DUnit подобная ситуация будет выглядеть вот так:
То есть создан не один тест «Add two numbers», а три. По одному для каждого случая.
Полный код примеров лежит вместе с библиотекой на github. Как я и обещал, DelphiSpec я не забрасываю и развиваю. Впереди мне предстоит тестирование и написание хотя бы краткой документации. А там уже и 1.0 не за горами :)
1. Alex W. Lulin
30 Дек 2013 11:49 пп
Роман, это РЕАЛЬНО КРУТО.
Жду не дождусь «продаж»…
2. Alex W. Lulin
5 Янв 2014 1:05 пп
Given_user_name_exists
мне кажется, что Given должно бы в базовую аксиоматику входить, как «конструкция языка», а не как «часть прикладного API»
3. Роман Янковский
5 Янв 2014 2:06 пп
Если честно, я не понял о чем ты. Given вроде как именно конструкция языка и есть.
4. Alex W. Lulin
6 Янв 2014 12:04 дп
«Given вроде как именно конструкция языка и есть.»
Только ты зачем-то «зашиваешь» её в «прикладное API».
Может быть я опять «не донёс».