Phillip Trelford's Array

POKE 36879,255

Functional Style BDD Steps

    Could a BDD framework be implemented simply as a fold over a sequence of lines in a document?
    Or in the words of Apple:

This changes everything. Again

marsattacks

Or in the words of Gojko Azdic:

Like anything else in F#, the primary use of this feature is to send it to 10 competitors whose brains you want to melt.

Let inception commence.


Fold

As defined on Wikipedia the Fold (higher-order function):

In functional programming, fold, also known variously as reduce, accumulate, compress or inject, is a family of higher-order functions that iterate an arbitrary function over a data structure in some order and build up a return value.

Or more succinctly defined via the F# List.fold signature on MSDN

  • ('State -> 'T -> 'State) -> 'State -> 'T list –> 'State

Fold high-order function implementation examples in F# and C#:

F#
C#

let rec fold f acc = function

    | [] -> acc

    | x :: xs -> fold f (f acc x) xs

public static TAcc Fold<TItem,TAcc>

    (Func<TAcc, TItem, TAcc> f,

     TAcc acc,

     IEnumerable<TItem> items)

{

    foreach (var item in items)

        acc = f(acc, item);

    return acc;

}

 

 

Thusly a BDD framework can be thought of simply as a fold that iterates over a document passing the lines or steps to an arbitrary matching function.

Signature:  fold: (‘context –> step –> ‘context) –> step list –> ‘context

With the accumulator value threaded between calls to the matching function representing the context, which can be explicitly scoped to the scenario under test!


Pattern Match

Given the following Feature document “Addition.txt”:

feature

And an immutable calculator type:

type Calculator = { Values : int list } with
    member this.Push n = {Values=n::this.Values}
    member this.Add() = {Values=[List.sum this.Values]}
    member this.Top = List.head this.Values

 

When folding over the lines in each scenario of the feature:

let feature = parse "Addition.txt"
feature.Scenarios
|> Seq.iter (fun scenario ->
    scenario.Steps
    |> List.fold performStep (Calculator())            
    |> ignore
)

 

And the following matching function is defined:

let performStep (calc:Calculator) (step,line:LineSource) =
    match step with
    | Given "I have entered (.*) into the calculator" [Int n] ->
        calc.Push n                        
    | When "I press add" [] -> 
        calc.Add ()
    | Then "the result should be (.*) on the screen" [Int n] ->
        Assert.AreEqual(n,calc.Top)
        calc            
    | _ -> sprintf "Unmatched line %d" line.Number |> invalidOp

 

Then the feature test succeeds!

inception


Parser

Parsing of the feature file is achieved using TickSpec’s parser module. TickSpec is an Open Source BDD framework written in F#. Underneath TickSpec’s parser is also implemented as a fold (well technically actually a scan) over a Gherkin feature document using regular expressions and Active Patterns.

To support the pattern matching function above the following Active Patterns are required:

[<AutoOpen>]
module Patterns =
    open System.Text.RegularExpressions
    let Regex input pattern =
        let r = Regex.Match(input,pattern)
        if r.Success then 
           Some [for i = 1 to r.Groups.Count-1 do yield r.Groups.[i].Value]
        else None
    let (|Given|_|) (pattern:string) (step) =
        match step with
        | GivenStep input -> Regex input pattern        
        | WhenStep _ | ThenStep _ -> None
    let (|When|_|) (pattern:string) (step) =
        match step with
        | WhenStep input -> Regex input pattern        
        | GivenStep _ | ThenStep _ -> None    
    let (|Then|_|) (pattern:string) (step) =
        match step with
        | ThenStep input -> Regex input pattern        
        | GivenStep _ | WhenStep _ -> None
    let (|Int|) s = System.Int32.Parse(s)

 

All the code to TickSpec including the parser and this sample (in Examples/Functional) are available at: http://tickspec.codeplex.com

 


NUnit

Finally the tests scenarios can be easily run within an NUnit test runner using the TestCaseSource attribute to parameterize a test method:

[<TestFixture>]
type AdditionFixture () =
    [<Test>]
    [<TestCaseSource(typeof<ScenarioSource>,"Scenarios")>]
    member this.TestScenario (scenario:ScenarioSource) =
        scenario.Steps |> Seq.fold performStep (Calculator.Create())
        |> ignore  
    member this.Scenarios =       
        let feature = parse "Addition.txt"        
        feature.Scenarios
        |> Seq.filter (fun scenario ->
            scenario.Tags |> Seq.exists ((=) "ignore") |> not
        )

 

Launch the NUnit Test Runner and the test passes:

NUnit


References

Cucumber style BDD Step Definitions with F#

This article describes how to define and execute BDD Step Definitions using F# in a similar, perhaps more concise, manner to using Ruby with Cucumber.

Behaviour Driven Development (BDD)

BDD is a relatively new Agile software development approach (circa 2003) that focuses on communication; encouraging collaboration between developers, QA and business participants; to help bridge the Business-IT alignment gap. Through discussion with stakeholders, scenarios in which the software will actually be used are written to build up a clear understanding of the desired behaviour.

Scenarios are specified in plain-text in a structured form composed of steps:

  • Given some context
  • When some event occurs
  • Then I expect some outcome

Developers and Testers use these scenarios as acceptance criteria to drive development. A feature is considered done when the tests pass for all of its scenarios.

Using a BDD framework, scenario specifications can be automated as acceptance tests, thereby creating living documentation that is in sync with the code. These days there is a plethora of Open Source BDD frameworks covering just about every programming language and platform.

Cucumber

Cucumber is probably the best known BDD framework at the moment. It executes plain-text files written in a business-readable domain-specific language (known as Gherkin) as automated tests. Each file describes a feature and its scenarios. During execution steps of a scenario are matched against Step Definitions composed of a regular expression and a function to execute. Cucumber is written in Ruby, and has benefited from Ruby’s light syntax and expressiveness to minimize the ceremony while defining step definitions:

Given /a customer buys a black jumper/ do
end

.Net BDD Frameworks

There are a number of Open Source BDD frameworks for.Net that can parse Gherkin based text specification files including:

Reflection

Typically .Net BDD frameworks take a reflection based approach, marking functions with attributes containing the regular expression to match against:

[Given(@"a customer buys a black jumper")]
public void GivenACustomerBuysABlackJumper()
{
}

 

StorEvil supports Reflection-based pattern matching representing spaces in C# method names as underscores:

public void Given_a_customer_buys_a_black_jumper()   
{ 
}

 

While TickSpec supports F# back-tick method names that can contain white space.

let [<Given>] ``a customer buys a black jumper`` () = ()

 

Note: A reflection based approach requires a compile and run cycle to test a feature. For iterative development in larger applications, Ruby developers may have the advantage, with Ruby being a dynamic language no compilation step is required. Matters can be improved for .Net developers by running individual tests in isolation using tools like Test Driven .Net or ReSharper, however this still does not mitigate the build step.

F#

F# is a powerful .Net language that ships with Visual Studio 2010. Although F# is a statically typed language, using type inference, developers can still benefit from a light and expressive syntax. F# can also execute scripts interactively. While as a first-class .Net programming language F# code interoperates easily with C# and VB.Net.

Using the TickSpec BDD framework (also written in F#) to parse the feature and scenarios; it is possible to specify step definitions concisely in a similar way to Cucumber for Ruby, i.e. without reflection:

Given "a customer buys a black jumper" <| fun []> ()

 

This approach allows step definitions to be executed in F# interactive

F# Interactive

Fragments of F# code can be executed as scripts using an F# interactive session which can be run from:

F# Interactive makes it easier for developers to take a more explorative approach to coding.

Example

 

Lets take the example from the front page of the Cucumber website and convert the code portions to F#:


Feature text file:

Feature 


Ruby step definition:
Calculator Steps 

F# step definition:

Given "I have entered (.*) into the calculator" <| fun [Int n] ->         
    calculator <- Calculator()
    calculator.Push n  

Ruby Calculator class:

Feature

F# Calculator class:

type Calculator () =
    let mutable values = []
    member this.Push(n) = values <- n :: values

Ruby Console output:

pending_thumb2

F# Interactive output:

image_thumb[1]

 

How it works

 

Given, When and Then are defined as F# functions with 2 parameters:

  1. s: a regular expression pattern string
  2. f: a handler function that takes a list of the string values matched

/// Registers specified pattern's handler function
let Given s f = RegisterStep givens s f
/// Registers specified pattern's handler function
let When s f = RegisterStep whens s f
/// Registers specified pattern's handler function
let Then s f = RegisterStep thens s f

 

Function RegisterStep records the pattern and handler in a dictionary:

let private givens, whens, thens = 
    Dictionary<_,_>(), Dictionary<_,_>(), Dictionary<_,_>()

let private RegisterStep 
        (stepDefinitions:Dictionary<_,_>) 
        (pattern:string) 
        (handler:string list -> unit) = 
    stepDefinitions.[pattern] <- handler

 

Feature text files are parsed using the TickSpec parser and scenario steps are tried against the registered pattern and function handlers:

/// Executes specified feature lines writing output to console
let Execute (lines:string[]) =  
    ...
    let feature = TickSpec.FeatureParser.parseFeature lines
    Console.WriteLine feature.Name
    feature.Scenarios 
    |> Seq.iter (fun scenario -> 
        Console.WriteLine scenario.Name
        scenario.Steps |> Seq.iter tryStep
    )

 

Inside the step definitions Active patterns can be used to parse strings:

let (|Int|) = function s -> System.Int32.Parse(s)

 

Allowing easy type conversion of parameters:

Then "the result should be (.*) on the screen" <| fun [Int n] ->
    pending()

 

All the above code is available in the Interactive project example of TickSpec on CodePlex.

Conclusions

 

Businesses are reporting real business value from adopting BDD; in Gojko Adzic’s forthcoming Specification by Example book he examines over 50 case studies of this style of technique. BDD is gaining real traction in the development community with plenty of talks at conferences and user groups on the subject, along with blog articles and books now available.

Hopefully this article has helped demonstrate the applicability of F# for developing BDD Step Definitions on the .Net platform. From experience, I believe that this can be a good way to gain value from introducing F# to an organization.

Regardless of your language preference, given that your business specifications could outlive your current platform and programming language, I’d recommend choosing a framework that is based on the well supported Gherkin business language, so that you are not locked in to a specific technology in the future.

References

 

BDD References:

F# Interactive References:

Lunar Landurz

In F# integer and floating point values can be associated with units of measure, typically used to indicate lengths, mass, etc. F# units of measure give compile time type safety with no runtime performance penalty!.Below is a playable Silverlight mini-game that applies units of measures in F# to 2D game mechanics.

Keys: Z = Left, X = Right, Space = Thrust

 

To complete the game you must land your craft on the flat ground (to make it a little easier the speed of landing and the orientation of the craft are not significant.

Note: this is a port of an XNA sample I wrote back in 2008.

Gravity

Use the Measure attribute to define your own measure types :

[<Measure>]
type m
[<Measure>]
type s

module Gravity = 
    let Earth = 9.8<m/s^2> // Standard Gravity
    let Lunar = Earth / 6.0 

Code: https://bitbucket.org/ptrelford/lunarlandurz

References: