DelphiSpec Library Announce
That said, I do think that the greatest potential benefit of DSLs comes when business people participate directly in the writing of the DSL code. The sweet spot, however is in making DSLs business-readable rather than business-writeable. If business people are able to look at the DSL code and understand it, then we can build a deep and rich communication channel between software development and the underlying domain.
In this post I’d like to announce DelphiSpec library. It was inspired by Cucumber. Actually, this library is the implementation of Gherkin language in Delphi. This implementation is not complete (consider it as an alpha version). Some features haven’t been implemented yet, but this project is still in development.
In a few words, the essence of the project is that DelphiSpec allows to turn the scenario into the appropriate unit test for DUnit:
Feature: Calculator Scenario: Add two numbers Given I have entered 50 in calculator And I have entered 70 in calculator When I press Add Then the result should be 120 on the screen Scenario: Add two numbers (fails) Given I have entered 50 in calculator And I have entered 50 in calculator When I press Add Then the result should be 120 on the screen Scenario: Multiply three numbers Given I have entered 5 in calculator And I have entered 5 in calculator And I have entered 4 in calculator WHEN I press mul Then the result should be 100 on the screen
I’ll underline that these are not tests but scenarios. In other words, this is the Behavior-Driven Development (BDD) in addition to the famous Test-Driven Development (TDD). Such scenarios serve as documentation, automated tests and development-aid – all rolled into one format. You should not describe internal system logic using scenarios: they should describe how user sees an application behavior.
Use of Gherkin is a good choice for DelphiSpec because it’s now considered as de-facto standard in the particular niche and if you took interest in it you can even buy a book with the best practices, tips on writing scenarios and examples in this language. Also there is lots of information on the Internet.
Let’s return to the example (the Calculator). The scenarios execution result in DUnit will look like:
How does this work? Gherkin is very small itself. Actually its only aim is to describe Given-When-Then formula. There are several keywords, all the rest could be customized.
We test a very simple class: a calculator. I will not post its code here, you can find it on github. The interesting thing is: how will the program understand and execute commands like “Given I have entered 50 in calculator”? Here comes the helper class which describes these steps (so-called “step definitions”). This is the helper class itself:
unit SampleCalculatorStepDefs; interface uses SampleCalculator, DelphiSpec.Attributes, DelphiSpec.StepDefinitions; type [_Feature('calculator')] TSampleCalculatorSteps = class(TStepDefinitions) private FCalc: TCalculator; public procedure SetUp; override; procedure TearDown; override; [_Given('I have entered (.*) in calculator')] procedure EnterInt(Value: string); [_When('I press Add')] procedure AddInt; [_When('I press Mul')] procedure MulInt; [_Then('the result should be (.*) on the screen')] procedure TestResult(Value: string); end; implementation uses System.SysUtils, TestFramework, DelphiSpec.Core; { TSampleCalculatorSteps } procedure TSampleCalculatorSteps.AddInt; begin FCalc.Add; end; procedure TSampleCalculatorSteps.EnterInt(Value: string); begin FCalc.Push(Value.ToInteger); end; procedure TSampleCalculatorSteps.MulInt; begin FCalc.Mul; end; procedure TSampleCalculatorSteps.SetUp; begin FCalc := TCalculator.Create; end; procedure TSampleCalculatorSteps.TearDown; begin FCalc.Free; end; procedure TSampleCalculatorSteps.TestResult(Value: string); begin if FCalc.Value <> Value.ToInteger then raise ETestFailure.Create('Incorrect result on calculator screen'); end; initialization RegisterStepDefinitionsClass(TSampleCalculatorSteps); end.
In fact, every step has a type (Given/When/Then) and the regular expression that describes the rest part of the step. Regular expressions help to extract the parameters which will be passed to the class methods to perform the relevant part of the scenario.
The only thing we need to do so that this system works is to add into project file (.dpr) the procedure call which receives the path to a folder which contains “.feature” files to process.
begin PrepareDelphiSpecs(TPath.Combine(ExtractFilePath(Application.ExeName), 'features'), True, 'EN'); DUnitTestRunner.RunRegisteredTests; end.
The last parameter (“EN”) allows us to specify a language in which we write the script. This is another interesting Gherkin possibility. Since, generally, there is no difference in what language the text is processed using regular expressions; it would be a good idea to translate a few keywords into different languages (using this XML).
So nothing prevents us from writting scenarios in any language:
Функционал: Калькулятор Сценарий: Сложить два числа Допустим я ввожу 50 на калькуляторе И я ввожу 70 на калькуляторе Когда я нажимаю СЛОЖИТЬ Тогда результат на экране должен быть 120
These are the very first steps, but I’m planning to implement full Gherkin functionality.
P.S. There are some comments in G+: https://plus.google.com/u/0/+RomanYankovsky/posts/2S789T49dX8