Even though I didn’t have much time lately, I managed to do some significant progress with DelphiSpec library over the last couple of weeks. Some features were introduced in my previous post, now please let me introduce new features.
First of all, there is a new quite cosmetic, but very convenient and nice feature – now it is possible to declare step definitions without the use of attributes (special thanks to Stefan Glienke).
In the previous post I showed you this syntax:
// sample scenario: "Given user ROOT exists" [Given_('user (.*) exists')] procedure MyProcName(const Name: string);
Though this still works, now it’s possible to do the same without attributes at all:
// sample scenario: "Given user ROOT exists" procedure Given_user_name_exists(const Name: string);
Thus you can use method name to declare step type and pattern. It is less flexible, but sometimes it is more convenient.
Also not only the string type is supported. This will work fine:
// sample scenario: "Given I have 3 apples" procedure Given_I_have_N_apples(N: Integer);
You are even allowed to pass an array:
// sample scenario: "Given I have a list 1,2,3,4" procedure Given_I_have_a_list_Ns(Ns: TArray<Integer>);
Or even array of records:
type TUserInfo = record Name: string; Password: string; Id: Integer; end; // sample scenario // Given users exist: // | id | name | password | // | 1 | Roman | pass1 | // | 2 | Other | pass2 | procedure Given_users_exist(Table: TArray<TUserInfo>);
Last example demonstrates a cool Gherkin data type – data table. Please note that this table is passed to a step definition method as a dynamic array of typed records. All type casting stuff is done by DelphiSpec and you don’t have to think about it… It is RTTI magic :)
One more type that Gherkin has and DelphiSpec supports is python-like multi-line strings. This kind of string is enclosed by three quotes and is passed to a step definition method as a regular Delphi string:
Given I have a blacklist: """ firstname.lastname@example.org email@example.com """
Besides there are a couple more interesting features.
Background allows you to add some context to all scenarios in a single feature. A Background is like an untitled scenario, containing a number of steps. The difference is when it is run: the background is run before each of your scenarios.
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
Also now you can not only describe a single scenario, but a more general Scenario outline:
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 |
The Scenario outline steps provide a template which never run directly. A Scenario Outline is run once for each row in the Examples section beneath it. The Scenario Outline uses placeholders, which are contained within angle brackets in the Scenario Outline’s steps
This is how a Scenario outline is showed in DUnit test tree:
“Add two numbers” has a single test for each case.
Full demo code is available on github. A plan for the future is to implement bindings to DUnitX and support both DUnit and DUnitX.