Rash thoughts about .NET, C#, F# and Dynamics NAV.


"Every solution will only lead to new problems."

Sunday, 22. January 2012


F# Legacy: Test implants

Filed under: F# — Steffen Forkmann at 11:51 Uhr

Legacy code is a problem in all languages, even F#. Zwinkerndes Smiley

The super awesome Ilker Cetinkaya published an excellent article about “test implants”. I really recommend to read his post before you read this one. It’s a really well written story called “The quest of the test”.

I destilled his nice little story to this small F# code:

We have a function a that is part of a third-party API and a function b which is part of our own legacy code base. The problem is: we want to check that b has called a. without changing b’s signature. Ilker suggested to use a “test implant”. Let’s try to do something similar with our small F# code. Since we are in the land of functional programming our idea is to implant another function into b. So let’s rename b into b’ and add the implant to the parameter list of b’.

Of course we restore b’s behaviour by utilizing b’:

As you can see, we didn’t change the signature nor the behaviour of b. This is a typical refactoring in F#. The program runs as before. Now we want to write our test:

I hope you can see the similarity between this and Ilkers solution. The only difference is that we don’t use new constructors here. I really like this since it brings you one step further to nice functional design. What do you think?

Tags: , , ,

Sunday, 11. July 2010


“Fake – F# Make” 1.33.0 released

Filed under: F#,FAKE - F# Make — Steffen Forkmann at 15:11 Uhr

Yesterday I released “FAKE – F# Make” version 1.33.0. This release has lots of small bug fixes and a couple of new features.

Important links:

Git helpers -Fake.Git.dll

Git is a distributed revision control system with an emphasis on speed. Git was initially designed and developed by Linus Torvalds for Linux kernel development. Every Git working directory is a full-fledged repository with complete history and full revision tracking capabilities, not dependent on network access or a central server.

[Wikipedia]

In the last couple of months I worked on small helper library for controlling Git. This library is now released as part of “FAKE – F# Make”. You can find the source code at http://github.com/forki/FAKE/tree/master/src/app/Fake.Git/.

Features:

  • Repository handling
    • init, clone
  • Submodules
    • init, clone, information about submodules
  • Branches
    • checkout, create, delete, merge, rebase, tag, pull, push, reset, commit, …
  • SHA1 calculation
Documentation generation with James Gregory’s docu tool

What’s a docu? A documentation generator for .Net that isn’t complicated, awkward, or difficult to use. Given an assembly and the XML that’s generated by Visual Studio, docu can produce an entire website of documentation with a single command.

[docu website]

Fake comes bundled with James Gregory’s documentations generator “docu”, which converts XML-Documentation comments into HTML files. All you need to do is downloading a template and calling the docu task inside your build script:

!+ (buildDir + "*.dll")
     |> Scan
     |> Docu (fun p ->
         {p with
             ToolPath = docuPath + "docu.exe"
             TemplatesPath = templatesSrcDir
             OutputPath = docsDir })

Since FAKE builds its own documentation with docu I started to add more (and hopefully better) XML doc comments. My plan is to describe more and more of the internal FAKE functions in the next releases. An updated HTML-document (generated via a docu task) can be found at http://www.navision-blog.de/fake/.

Side by side specification

For Test-driven development (TDD) it’s sometimes nice to have the specifications next to the implementation files since the specs are considered as documentation.

By using a tool like VSCommands it is possible to group the implementation with the specs (see also http://gist.github.com/457248).

This “side by side specification” makes TDD a lot easier but of course we don’t want to deploy the specification classes and the test data.

Side by side specification ==> After "RemoveTestFromProject"

FAKE has a new feature which automatically removes all specification files and test framework references according to a given convention:

Target "BuildApp" (fun _ –>
      !+ @"src\app\**\*.csproj"
         |> Scan
         |> Seq.map (
             RemoveTestsFromProject
                 AllNUnitReferences      // a default references convention
                 AllSpecAndTestDataFiles // a default file convention
                 )
         |> MSBuildRelease buildDir "Build"
         |> Log "AppBuild-Output: "
)

The conventions are simple functions and can be customized e.g.:

/// All Spec.cs or Spec.fs files and all files containing TestData
let AllSpecAndTestDataFiles elementName (s:string) =
     s.EndsWith "Specs.cs" ||
       s.EndsWith "Specs.fs" ||
       (elementName = "Content" && s.Contains "TestData")
Miscellaneous
  • SQL Server helpers are moved to Fake.SQL.dll
    • Additional functions for attaching and detaching databases.
  • FileHelper.CopyCached function was added
    • Copies the files from a cache folder. If the files are not cached or the original files have a different write time the cache will be refreshed.
  • EnvironmentHelper.environVarOrDefault added
    • Retrieves the environment variable or a given default.
  • Fixed Issue 3: toRelativePath calculates paths with ..\..\ if needed
  • Added a build time report to the build output.
  • XPathReplace and XMLPoke tasks added.
    • Replaces text in an XML file at the location specified by an XPath expression.
  • ILMerge task added
  • Windows Installer XML (WiX) task added
Tags: , , , , , , , ,

Thursday, 20. May 2010


Bericht vom Ersten .NET Coding Dojo in Hamburg

Filed under: C#,Veranstaltungen — Steffen Forkmann at 6:37 Uhr

Gestern fand das erste .NET Coding Dojo in Hamburg statt und es war aus meiner Sicht ein voller Erfolg. Als erstes möchte ich mich an dieser Stelle bei der Firma masters of arts für die Räumlichkeit und natürlich bei allen Teilnehmer für die aktive Mitarbeit bedanken.

Erklärungen

Durchgeführt haben wir das Dojo im Randori-Stil, d.h. es gab einen Entwickler, einen “Co-Piloten” und das Publikum. Nach jeweils 5 Minuten bzw. jedem neuen Testfall wurden die Positionen mit neuen Teilnehmer aus dem Publikum getauscht.

Nach einer kurzen allgemeinen Einführung in das Thema “Coding Dojo” habe ich die Aufgabenstellungen der Kata.FizzBuzz und Kata.DictionaryReplacer vorgestellt. Durch kurze Abstimmung haben wir dann (vermutlich durch meine Wortwahl beeinflusst) die Kata.DictionaryReplacer gewählt.

Mit der Wahl dieser Kata war ich nicht ganz unglücklich, da wir DictionaryReplacer schon im Online Dojo durchgenommen haben und ich deshalb die Fallstricke schon etwas einschätzen konnte.

Kata.DictionaryReplacer

Create a method that takes a string and a dictionary,
and replaces every key in the dictionary pre and suffixed with a dollar sign,
with the corresponding value from the Dictionary.

Tests

input : "",
          dict empty
output: ""

input : "$temp$", 
           dict ["temp", "temporary"]
output: "temporary"

input : "$temp$ here comes the name $name$",
           dict ["temp", "temporary"] ["name", "John Doe"]
output : "temporary here comes the name John Doe"

[codingdojo.org]

Nach kurzer Einführung in die Vorgehensweise des Test-Driven Developments (TDD) und Diskussion über sinnvolles Naming ging es dann auch richtig in die Entwicklung. Die Kata eignet sich in dieser Form auch sehr schön um tatsächlich “Test first” zu arbeiten. Die Implementierung folgt quasi als logische Konsequenz.

Das Publikum

Interessant und ungleich komplizierter wurde es dann als wir eine zusätzliche Anforderung eingebaut haben. Da es sich bei der Kata um eine Art Templatesystem handelt liegt es nahe auch in den Values des Wörterbuchs neue Keys zu erlauben und somit eine beliebige Ersetzungstiefe zu erreichen. Diese Anforderung ist ein wunderbares Beispiel dafür wie sehr man mit Aufwandsabschätzungen daneben liegen kann. 😉

Guter Rat ist teuer

Die rekursive Ersetzung wurde noch sehr schnell gelöst, aber richtig schwer haben wir uns dann mit der Erkennung von zyklischen Ersetzungen und der daraus folgenden Endlosschleife getan. Nach und nach wurden immer kompliziertere Lösungsmöglichkeiten genannt, die aber in der gegebenen Zeit nicht fehlerfrei umgesetzt werden konnten. Als Folge haben wir immer noch einen Test “rot”. Wer Lust hat kann sich also die Quellen vom github Repository ziehen und als Hausaufgabe den verbleibenden Test “grün” machen.

In der Nachbetrachtung haben wir noch einige Sachen festgestellt:

Was lief gut?
  • Die Rotation der Teilnehmer klappte problemlos
  • Lösungsideen sprudelten förmlich aus dem Publikum
  • Interessante Edge-Cases wurden gefunden
  • Viele kleine Tipps (z.B. Resharper Shortcuts) wurden ausgetauscht
  • TDD wurde als erfolgreich für die Kata angesehen
  • Die Randori-Form sorgt für Aktivität
  • Ganz wichtig: Es hat Spaß gemacht!
Was wollen wir besser machen?
  • Schneller den ersten Test schreiben
  • Intensivere Diskussion des Interfaces
  • Noch mehr Wert auf das Naming legen
  • Versuchen die einfachste Lösung zu wählen
  • Mehr Wert auf Refactoring legen
    • wurde etwas vernachlässigt, da wir viel Zeit an der Endlosschleife verbraucht haben
  • Die Rollen Driver, Co-Pilot und Publikum klarer trennen
  • Nach jedem implementierten Testcase bzw. jeder Rotation der Teilnehmer in das git Repository einchecken
  • Von Anfang an externe Tastatur und Maus für den Laptop bereit stellen
  • Internetverbindung um Syntaxfrage schneller klären zu können

Als möglichen Termin für das Dojo haben wir jetzt grob jeweils den 3. Mittwoch im Monat vorgeschlagen. Über die Xing-Gruppe der .NET User Group Hamburg werden wir natürlich auch wieder entsprechende Einladungen verschicken.

Tags: , , ,

Saturday, 24. April 2010


Solving KataYahtzee with F# and NaturalSpec

Filed under: F#,Informatik,Kata — Steffen Forkmann at 19:04 Uhr

Today I’m starting a new blog post series about solving code katas in F# and with the help of my NaturalSpec project. A code kata is a programming exercise which helps to improve your skills through practice and repetition. In this series we want to use the Test Driven Development TDD approach which means in the context of NaturalSpec that we have to write our specs before we implement the algorithm.

Problem Description

“The game of yahtzee is a simple dice game. Each round, each player rolls five six sided dice. The player may choose to reroll some or all of the dice up to three times (including the original roll). The player then places the roll at a category, such as ones, twos, sixes, pair, two pairs etc. If the roll is compatible with the score, the player gets a score for this roll according to the rules. If the roll is not compatible, the player gets a score of zero for this roll.

The kata consists of creating the rules to score a roll in any of a predefined category. Given a roll and a category, the final solution should output the score for this roll placed in this category.”

[codingdojo.org]

Category 1 – Ones, Twos, Threes, Fours, Fives, Sixes

“Ones, Twos, Threes, Fours, Fives, Sixes: The player scores the sum of the dice that reads one, two, three, four, five or six, respectively. For example, 1, 1, 2, 4, 4 placed on "fours" gives 8 points.”

After reading this category description we could come up with the following spec:

module Yahtzee.Specs

 

open NaturalSpec

 

let placed_on category list =

    printMethod category

    calcValue category list

 

[<Scenario>]    

let “Given 1,1,2,4,4 placed on "fours" gives 8 points.“ () =  

    Given (1, 1, 2, 4, 4)

      |> When (placed_on Fours)

      |> It should equal 8

      |> Verify

Since we really want to implement six different categories we should also add some more scenarios like this one:

[<Scenario>]    

let “Given 1,1,6,4,6 placed on "sixes" gives 12 points.“ ()=  

    Given (1, 1, 6, 4, 6)

      |> When (placed_on Sixes)

      |> It should equal 12

      |> Verify

 

// …

Now we have some specs but they will all fail since we don’t have anything implemented yet. So we have to come up with a model of dice rolls and categories. As the specs suggests we model the dice roll as a tuple of ints and the category as a discriminated union:

module Yahtzee.Model

 

type Roll = int * int * int * int * int

 

type Category =

| Ones

| Twos

| Threes

| Fours

| Fives

| Sixes  

The tuple is a natural choice for the dice roll, but for easier calculation we add a helper function which converts it into a list. This allows use to use the standard list functions and therefore summing the values becomes trivial:

let toList (roll:Roll) =

    let a,b,c,d,e = roll

    [a;b;c;d;e]

 

let sumNumber number =

    Seq.filter ((=) number)

      >> Seq.sum

 

let calcValue category roll =

    let list = toList roll

    match category with

    | Ones   -> sumNumber 1 list

    | Twos   -> sumNumber 2 list

    | Threes -> sumNumber 3 list

    | Fours  -> sumNumber 4 list

    | Fives  -> sumNumber 5 list

    | Sixes  -> sumNumber 6 list

Now we can run our scenarios with any NUnit runner. I’m using the default NUnit GUI runner here, which gives me a picture like this:

Both specs in NUnit

Category 2 – Pair

“Pair: The player scores the sum of the two highest matching dice. For example, 3, 3, 3, 4, 4 placed on "pair" gives 8.”

The kata description gives us some new scenarios. As seen above we should specify them before writing the code.

[<Scenario>]    

let “Given 3,3,3,4,4 placed on "pair" gives 8.“ () =  

    Given (3, 3, 3, 4, 4)

      |> When (placed_on Pair)

      |> It should equal 8

      |> Verify

 

[<Scenario>]    

let “Given 5,3,5,4,4 placed on "pair" gives 10.“ () =  

    Given (5, 3, 5, 4, 4)

      |> When (placed_on Pair)

      |> It should equal 10

      |> Verify   

 

[<Scenario>]    

let “Given 1,2,3,4,5 placed on "pair" gives 0.“ () =  

    Given (1, 2, 3, 4, 5)

      |> When (placed_on Pair)

      |> It should equal 0

      |> Verify     

Since we use a new category we now have to extend our model and the calcValue function:

type Category =

| Ones

  // …

| Sixes

| Pair

 

// …

let sumAsPair list number =

    let numberCount =

        list

          |> Seq.filter ((=) number)

          |> Seq.length

 

    if numberCount >= 2 then 2 * number else 0

 

let calcValue category roll =

    let list = toList roll

    match category with

    | Ones   -> sumNumber 1 list

        // …

    | Sixes  -> sumNumber 6 list

    | Pair   ->

        [1..6]

          |> Seq.map (sumAsPair list)

          |> Seq.max  

Category 3 – Two pairs

“Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, the player scores 0. For example, 1, 1, 2, 3, 3 placed on "two pairs" gives 8.”

[<Scenario>]    

let “Given 1,1,2,3,3 placed on "two pair" gives 8.“ () =  

    Given (1, 1, 2, 3, 3)

      |> When (placed_on TwoPair)

      |> It should equal 8

      |> Verify

 

[<Scenario>]    

let “Given 1,6,6,3,3 placed on "two pair" gives 18.“ () =  

    Given (1, 6, 6, 3, 3)

      |> When (placed_on TwoPair)

      |> It should equal 18

      |> Verify

 

[<Scenario>]    

let “Given 1,1,2,4,3 placed on "two pair" gives 0.“ () =  

    Given (1, 1, 2, 4, 3)

      |> When (placed_on TwoPair)

      |> It should equal 0

      |> Verify 

Implementing this category is a little bit tricky but with the help of our Pair function and some more standard sequence combinators we can get our spec green:

type Category =

| Ones

  // …

| TwoPair

 

let allPairs =

    [for i in 1..6 do

       for j in 1..6 -> i,j]

 

let calcValue category roll =

    // …

    | TwoPair   ->

        allPairs

          |> Seq.filter (fun (a,b) -> a <> b)

          |> Seq.map (fun (a,b) ->

                let a’ = sumAsPair list a

                let b’ = sumAsPair list b

                if a’ = 0 || b’ = 0 then 0 else a’ + b’)

          |> Seq.max    

Category 4 – Three of a kind

“Three of a kind: If there are three dice with the same number, the player scores the sum of these dice. Otherwise, the player scores 0. For example, 3, 3, 3, 4, 5 places on "three of a kind" gives 9.”

[<Scenario>]    

let “Given 3,3,3,4,5 placed on "three of a kind" gives 9“()=  

    Given (3, 3, 3, 4, 5)

      |> When (placed_on ThreeOfAKind)

      |> It should equal 9

      |> Verify

 

[<Scenario>]    

let “Given 3,4,3,4,5 placed on "three of a kind" gives 0“()=  

    Given (3, 4, 3, 4, 5)

      |> When (placed_on ThreeOfAKind)

      |> It should equal 0

      |> Verify

Now it is time to refactor our code. The sumAsPair function should be extended to a sumAsTuple function:

type Category =

| Ones

  // …

| ThreeOfAKind

 

let sumAsTuple value list number =

    let numberCount =

        list

          |> Seq.filter ((=) number)

          |> Seq.length

 

let takeBestTuple value list =

    [1..6]

        |> Seq.map (sumAsTuple value list)

        |> Seq.max 

    if numberCount >= value then value * number else 0

 

let calcValue category roll =

      // …

    | Pair   -> takeBestTuple 2 list

    | TwoPair   ->

        allPairs

          |> Seq.filter (fun (a,b) -> a <> b)

          |> Seq.map (fun (a,b) ->

                let a’ = sumAsTuple 2 list a

                let b’ = sumAsTuple 2 list b

                if a’ = 0 || b’ = 0 then 0 else a’ + b’)

          |> Seq.max

    | ThreeOfAKind –> takeBestTuple 3 list

Category 5 – Four of a kind

“Four of a kind: If there are four dice with the same number, the player scores the sum of these dice. Otherwise, the player scores 0. For example, 2, 2, 2, 2, 5 places on "four of a kind" gives 8.”

[<Scenario>]    

let “Given 2,2,2,2,5 placed on "four of a kind" gives 8“ ()=  

    Given (2, 2, 2, 2, 5)

      |> When (placed_on FourOfAKind)

      |> It should equal 8

      |> Verify

 

[<Scenario>]    

let “Given 2,6,2,2,5 placed on "four of a kind" gives 0“ ()=  

    Given (2, 6, 2, 2, 5)

      |> When (placed_on FourOfAKind)

      |> It should equal 0

      |> Verify  

With the help of the takeBestTuple function this becomes trivial:

type Category =

| Ones

  // …

| FourOfAKind

 

let calcValue category roll =

      // …

    | FourOfAKind  -> takeBestTuple 4 list

 

Category 6 – Small straight

“Small straight: If the dice read 1,2,3,4,5, the player scores 15 (the sum of all the dice), otherwise 0.”

[<Scenario>]    

let “Given 1,2,3,4,5 placed on "Small Straight" gives 15“()=  

    Given (1,2,3,4,5)

      |> When (placed_on SmallStraight)

      |> It should equal 15

      |> Verify

 

[<Scenario>]    

let “Given 1,2,5,4,3 placed on "Small Straight" gives 15“()=  

    Given (1,2,5,4,3)

      |> When (placed_on SmallStraight)

      |> It should equal 15

      |> Verify

 

[<Scenario>]    

let “Given 1,2,6,4,3 placed on "Small Straight" gives 0“()=  

    Given (1,2,6,4,3)

      |> When (placed_on SmallStraight)

      |> It should equal 0

      |> Verify 

As in all the above scenarios we don’t assume any specific order in our rolls but for this category it is easier to test if the data is sorted:

type Category =

| Ones

  // …

| SmallStraight

 

let calcValue category roll =

      // …

    | SmallStraight ->

        match list |> List.sort with

        | [1;2;3;4;5] -> 15

        | _ -> 0

Category 7 – Large straight

“Large straight: If the dice read 2,3,4,5,6, the player scores 20 (the sum of all the dice), otherwise 0.”

[<Scenario>]    

let “Given 2,3,4,5,6 placed on "Large Straight" gives 20“()=  

    Given (2,3,4,5,6)

      |> When (placed_on LargeStraight)

      |> It should equal 20

      |> Verify

 

[<Scenario>]    

let “Given 6,2,5,4,3 placed on "Large Straight" gives 20“()=  

    Given (6,2,5,4,3)

      |> When (placed_on LargeStraight)

      |> It should equal 20

      |> Verify

 

[<Scenario>]    

let “Given 1,2,6,4,3 placed on "Large Straight" gives 0“()=  

    Given (1,2,6,4,3)

      |> When (placed_on LargeStraight)

      |> It should equal 0

      |> Verify 

Of course the implementation is exactly the same as for the small straight:

type Category =

| Ones

  // …

| LargeStraight

 

let calcValue category roll =

      // …

    | LargeStraight ->

        match list |> List.sort with

        | [2;3;4;5;6] -> 20

        | _ -> 0

Category 8 – Full house

“Full house: If the dice are two of a kind and three of a kind, the player scores the sum of all the dice. For example, 1,1,2,2,2 placed on "full house" gives 8. 4,4,4,4,4 is not "full house".”

[<Scenario>]    

let “Given 1,1,2,2,2 placed on "full house" gives 8.“ () =  

    Given (1,1,2,2,2)

      |> When (placed_on FullHouse)

      |> It should equal 8

      |> Verify

 

[<Scenario>]    

let “Given 4,4,4,4,4 placed on "full house" gives 0.“ () =  

    Given (4,4,4,4,4)

      |> When (placed_on FullHouse)

      |> It should equal 0

      |> Verify

 

[<Scenario>]    

let “Given 1,1,2,3,2 placed on "full house" gives 0.“ () =  

    Given (1,1,2,3,2)

      |> When (placed_on FullHouse)

      |> It should equal 0

      |> Verify

Implementing the FullHouse category is easy if we reuse our solutions to the Two pairs category:

type Category =

| Ones

  // …

| FullHouse

 

let takeBestCombo value1 value2 list =

    allPairs

        |> Seq.filter (fun (a,b) -> a <> b)

        |> Seq.map (fun (a,b) ->

            let a’ = sumAsTuple value1 list a

            let b’ = sumAsTuple value2 list b

            if a’ = 0 || b’ = 0 then 0 else a’ + b’)

        |> Seq.max

 

let calcValue category roll =

      // …

    | TwoPair   -> takeBestCombo 2 2 list

      // …

    | FullHouse   -> takeBestCombo 2 3 list

Category 9 – Yahtzee

“Yahtzee: If all dice are the have the same number, the player scores 50 points, otherwise 0.”

Here we can use NaturalSpec’s ScenarioTemplates in order to specify all Yahtzees:

[<ScenarioTemplate(1)>]

[<ScenarioTemplate(2)>]

[<ScenarioTemplate(3)>]

[<ScenarioTemplate(4)>]

[<ScenarioTemplate(5)>]

[<ScenarioTemplate(6)>]

let “Given n,n,n,n,n placed on "Yahtzee" gives 50.“ n =  

    Given (n,n,n,n,n)

      |> When (placed_on Yahtzee)

      |> It should equal 50

      |> Verify

 

[<Scenario>]    

let “Given 1,1,1,2,1 placed on "Yahtzee" gives 50.“ () =  

    Given (1,1,1,2,1)

      |> When (placed_on Yahtzee)

      |> It should equal 0

      |> Verify

The implementation is pretty easy:

type Category =

| Ones

  // …

| Yahtzee

 

let calcValue category roll =

      // …

    | Yahtzee ->

        let a,b,c,d,e = roll

        if a = b && a = c && a = d && a = e then 50 else 0

Category 10 – Chance

“Chance: The player gets the sum of all dice, no matter what they read.”

[<Scenario>]    

let “Given 1,1,1,2,1 placed on "Chance" gives 6.“ () =  

    Given (1,1,1,2,1)

      |> When (placed_on Chance)

      |> It should equal 6

      |> Verify

 

[<Scenario>]    

let “Given 1,6,1,2,1 placed on "Chance" gives 11.“ () =  

    Given (1,6,1,2,1)

      |> When (placed_on Chance)

      |> It should equal 11

      |> Verify

This seems to be the easiest category as we only have to sum the values:

type Category =

| Ones

  // …

| Chance

 

let calcValue category roll =

      // …

    | Chance -> List.sum list

Conclusion

We used a lot of F#’s sequence combinators, pattern matching and discriminated unions in this kata. I think this shows that F# is very well suited for such a problem and with NaturalSpec we can easily use a TDD/BDD approach.

The complete source code can be found in the NaturalSpec repository.

If you want to know more about a specific part of the kata or NaturalSpec feel free to contact me.

Tags: , , , , , , ,

Sunday, 8. November 2009


"Getting started" with NaturalSpec – (Updated 08.11.2009)

Filed under: .NET,F#,NaturalSpec — Steffen Forkmann at 10:48 Uhr

In my last article (Introducing NaturalSpec – A Domain-specific language (DSL) for testing) I used NaturalSpec in two small samples. This time I will show how we can set up a NaturalSpec environment to write our first automatically testable scenarios.

1. Choosing an IDE

The first step is to choose an integrated development environment for NaturalSpec. At the current project status you should be able to use NaturalSpec with Visual Studio 2008, Visual Studio 2010 beta 2, the freely available Visual Studio 2008 Shell or the free IDE SharpDevelop 3.0.

2. Installing the testing framework

As NaturalSpec uses NUnit as the underlying testing framework we have to install NUnit 2.5. I also recommend installing TestDriven.Net in order to get a Unit Test runner within Visual Studio.

3. Installing F#

NaturalSpec is completely written in F# and all specs will also be written in F#. This doesn’t imply you have to learn programming in F# but we need the F# compiler to get things working. You can download the F# October 2009 CTP from the Microsoft F# Developer Center.

4. Downloading the latest version of NaturalSpec

You can download a .zip with the latest NaturalSpec libraries from GoogleCode.

5. Creating a spec

This part is written for using Visual Studio 2008. If you use SharpDevelop or Visual Studio 2008 Shell this might differ in some detail.

Start Visual Studio 2008 and create a new F# class library.

Creating a spec project

Rename Module1.fs in ListSpec.fs and delete script.fsx from the project:

Solution explorer

Create a folder “Lib” and unzip the NaturalSpec libraries into it.

Add NaturalSpec.dll and nunit.framework.dll as references to your project:

Adding project references

Copy the following code into ListSpec.fs:

module ListSpec
open NaturalSpec

[<Scenario>]
let When_removing_an_3_from_a_small_list_it_should_not_contain_3() =
  Given [1;2;3;4;5]
    |> When removing 3
    |> It shouldn't contain 3
    |> Verify

If you have TestDriven.Net installed you can run your spec via right click in the solution explorer:

Run spec with TestDriven.net

If you don’t like the TestDriven.Net test runner you might want to use the NUnit GUI runner. The output should look like:

NUnit Gui runner

In addition the test runner should produce a Spec output file with the name “Spec.txt” within the same folder.

Summary

In a minimal environment you need SharpDevelop, the F# compiler, NUnit and the NaturalSpec libraries for using NaturalSpec.

In the next post I will show how you can use NaturalSpec to create a spec for C# projects.

Tags: , , , , ,

Saturday, 28. February 2009


Parameterized Scenarios with NaturalSpec

Filed under: F#,NaturalSpec — Steffen Forkmann at 16:46 Uhr

I wrote a lot about NaturalSpec in my last articles. This time I will show how we can use parameterized scenarios.

1. Using predefined scenarios

By writing predefined parameterized scenarios we can easily create a scenario suite with lots of different test cases:

// predefined scenario
let factorialScenario x result =
  Given x
    |> When calculating factorial
    |> It should equal result

[<Scenario>]
let When_calculation_factorial_of_1() =
  factorialScenario 1 1
    |> Verify   

[<Scenario>]
let When_calculation_factorial_of_10() =
  factorialScenario 10 3628800
    |> Verify

If we run these scenarios with NUnit we will get the following output:

Scenario: When calculation factorial of 1

  – Given 1

    – When calculating factorial

       => It should equal 1

==> OK

==> Time: 0.0093s

Scenario: When calculation factorial of 10

  – Given 10

    – When calculating factorial

       => It should equal 3628800

==> OK

==> Time: 0.0018s

2. Using the ScenarioTemplate attribute

The second and shorter option is to use the ScenarioTemplate attribute, which is inherited from NUnit’s new TestCase attribute:

// with ScenarioTemplate Attribute
[<ScenarioTemplate(1, 1)>]
[<ScenarioTemplate(2, 2)>]
[<ScenarioTemplate(5, 120)>]
[<ScenarioTemplate(10, 3628800)>]
let When_calculating_fac_(x,result) =
  Given x
    |> When calculating factorial
    |> It should equal result
    |> Verify

This code will create 4 different scenarios, which NUnit will display and report separately:

NUnit runner reports test cases

3. Using ScenarioSource

The third option is to use the ScenarioSource attribute. Here we define a function which generates TestData:

/// with a scenario source      
let MyTestCases =
  TestWith 12 3 4
    |> And 12 4 3
    |> And 12 6 2
    |> And 1200 40 30
    |> And 0 0 0 |> ShouldFailWith (typeof<System.DivideByZeroException>)

And then we have to tell NaturalSpec which TestData a scenario should use:

[<Scenario>]
[<ScenarioSource "MyTestCases">]
let When_dividing a b result =
 Given a 
   |> When dividing_by b
   |> It should equal result
   |> Verify
 NaturalSpec with ScenarioSource  
Summary

Sometime it makes sense to test a scenario with a bunch of different parameters. We can use the ScenarioTemplate attribute to easily parameterize our scenarios. If we want more flexibility we can use predefined scenarios with custom parameters or the ScenarioSource attribute.

Tags: , , , ,

Monday, 23. February 2009


Using NaturalSpec to create a spec for C# projects (Updated 08.11.2009)

Filed under: F#,NaturalSpec — Steffen Forkmann at 18:07 Uhr

In my last two articles I gave an introduction in NaturalSpec and showed how to get started. This time I will show how we can use NaturalSpec to write automatically testable scenarios for C# projects.

Like the TDD principle “Write the tests first” we should write our spec first and use the “Red-Green-Refactor” method.

"Red" – Create a spec scenario that fails

At first I created a F# class library project called “Spec.CarSelling” and added project references to NaturalSpec.dll and nunit.framework.dll (see “Getting started” for further explanations).

Now I can write my first scenario:

// 1. define the module
module CarSpec
// 2. open the NaturalSpec namespace
open NaturalSpec // 3. open project namespace open CarSellingLib // 4. define a test context let Bert = new Dealer("Bert") // 5. create a method in BDD-style let selling_a_car_for amount (dealer:Dealer) = printMethod amount dealer.SellCar amount // 6. create a scenario [<Scenario>] let When_selling_a_car_for_30000_it_should_equal_my_DreamCar() = As Bert |> When selling_a_car_for 30000 |> It should equal (new Car(CarType.BMW, 200)) |> Verify

At this stage the scenario is ready but doesn’t compile. This means we are ready with the "Red"-stage.

"Green" – Make the test the pass

In order to get the test green we have to create a C# class library called CarSellingLib and define the enum CarType and the classes Dealer and Car. Sticking to the YAGNI-principle we implement only the minimum to get the spec green (and ToString()-members for the output functionality).

namespace CarSellingLib
{
    public enum CarType
    {
        BMW
    }
}

namespace CarSellingLib
{
    public class Car
    {
        public Car(CarType type, int horsePower)
        {
            Type = type;
            HorsePower = horsePower;
        }

        public CarType Type { get; set; }
        public int HorsePower { get; set; }

        public override string ToString()
        {
            return string.Format("{0} ({1} HP)", Type, HorsePower);
        }

        public override bool Equals(object obj)
        {
            var y = obj as Car;
            if(y == null) return false;
            return Type == y.Type && HorsePower == y.HorsePower;
        }
    }
}
using System;

namespace CarSellingLib
{
    public class Dealer
    {
        public Dealer(string name)
        {
            Name = name;
        }

        public string Name { get; set; }

        public Car SellCar(int amount)
        {
            return new Car(CarType.BMW, 200);
        }

        public override string ToString()
        {
            return Name;
        }
    }
}


When we add a project reference to our spec-project the UnitTests should pass and we have completed the "Green" step. (See "Getting started" if you don’t know how to run the spec.) Now we can add some more scenarios to our spec:

// 1. define the module 
module CarSpec
// 2. open NaturalSpec-Namespace
open NaturalSpec

// 3. open project namespace
open CarSellingLib

// 4. define a test context
let Bert = new Dealer("Bert")

// define reusable values
let DreamCar = new Car(CarType.BMW, 200)
let LameCar = new Car(CarType.Fiat, 45)

// 5. create a method in BDD-style
let selling_a_car_for amount (dealer:Dealer) =
  printMethod amount
  dealer.SellCar amount

// 6. create a scenario
[<Scenario>]
let When_selling_a_car_for_30000_it_should_equal_the_DreamCar() =
  As Bert
    |> When selling_a_car_for 30000
    |> It should equal DreamCar
    |> It shouldn't equal LameCar
    |> Verify      

[<Scenario>]
let When_selling_a_car_for_19000_it_should_equal_the_LameCar() =
  As Bert
    |> When selling_a_car_for 19000
    |> It should equal LameCar
    |> It shouldn't equal DreamCar
    |> Verify

// create a scenario that expects an error
[<Scenario>]
[<Fails_with "Need more money">]
let When_selling_a_car_for_1000_it_should_fail_with_Need_More_Money() =
  As Bert
    |> When selling_a_car_for 1000
    |> Verify

Now we are in the “Red”-Phase again.

"Refactor" – rearrange your code to eliminate duplication and follow patterns

After making the spec "Green" and doing some refactoring the project code could look like this:

namespace CarSellingLib
{
    public enum CarType
    {
        Fiat,
        BMW
    }
}

namespace CarSellingLib
{
    public class Car
    {
        public Car(CarType type, int horsePower)
        {
            Type = type;
            HorsePower = horsePower;
        }

        public CarType Type { get; set; }
        public int HorsePower { get; set; }

        # region ToString, Equals 

        public override string ToString()
        {
            return string.Format("{0} ({1} HP)", Type, HorsePower);
        }

        public override bool Equals(object obj)
        {
            var y = obj as Car;
            if(y == null) return false;
            return Type == y.Type && HorsePower == y.HorsePower;
        }

        #endregion
    }
}

using System;

namespace CarSellingLib
{
    public class Dealer
    {
        public Dealer(string name)
        {
            Name = name;
        }

        public string Name { get; set; }

        public Car SellCar(int amount)
        {
            if (amount > 20000)
                return new Car(CarType.BMW, 200);

            if (amount > 3000)
                return new Car(CarType.Fiat, 45);

            throw new Exception("Need more money");
        }

        public override string ToString()
        {
            return Name;
        }
    }
}

The spec output should look like the following:

Scenario: When selling a car for 1000 it should fail with Need More Money

– Should fail…
– As Bert
– When selling a car for 1000

Scenario: When selling a car for 19000 it should equal the LameCar

– As Bert
– When selling a car for 19000
=> It should equal Fiat (45 HP)
=> It should not equal BMW (200 HP)
==> OK

Scenario: When selling a car for 30000 it should equal my DreamCar

– As Bert
– When selling a car for 30000
=> It should equal BMW (200 HP)
==> OK

Scenario: When selling a car for 30000 it should equal the DreamCar

– As Bert
– When selling a car for 30000
=> It should equal BMW (200 HP)
=> It should not equal Fiat (45 HP)
>==> OK

4 passed, 0 failed, 0 skipped, took 1,81 seconds (NUnit 2.5).

Summary

I showed how we can use NaturalSpec for the Red-Green-Refactor process of C# projects and how easy it is to get a spec in natural language.

Tags: , , , , ,

Introducing NaturalSpec – A Domain-specific language (DSL) for testing – Part I

Filed under: C#,F#,NaturalSpec,Tools — Steffen Forkmann at 11:31 Uhr

Test-Driven development (TDD) is a well known software development technique and follows the mantra “Red-Green-Refactor”. Behavior-Driven Development (BDD) is a response to TDD and introduces the idea of using natural language to express the Unit Test scenarios.

There are a lot of popular testing frameworks around which can be used for BDD including xUnit.net ,NUnit, StoryQ, MSpec, NSpec and NBehave. Most of them can be used with fluent interfaces and therefore provides a good readability of the sources. Some of them even provide the possibility to generate a spec in natural language out of passed Unit tests.

What is a spec?

“A specification is an explicit set of requirements to be satisfied by a material, product, or service.”

American Society for Testing and Materials (ASTM) definition

A spec is an important document for the communication process – it enables domain experts to communicate with developers. But how can you verify the compliance with the spec? The answer is: you have to write unit tests. Even with the mentioned frameworks there is a lot of work to do in order to translate a spec scenario into a Unit Test.

Question 7 in the famous Joel Test is “Do you have a spec?”.

The idea of NaturalSpec is to give domain experts the possibility to express their scenarios directly in compilable Unit Test scenarios by using a Domain-specific language (DSL) for Unit Tests. NaturalSpec is completely written in F# – but you don’t have to learn F# to use it. You don’t even have to learn programming at all.

Example 1 – Specifying a list

Let’s consider a small example. If we want to test a new List implementation a spec could look like this:

[<Scenario>]
let When_removing_an_3_from_a_small_list_it_should_not_contain_3() =
  Given [1;2;3;4;5]              // “Arrange” test context
    |> When removing 3           // “Act|> It shouldn't contain 3    // “Assert|> It should contain 4       // another assertion
    |> Verify                    // Verify scenario

I used BDD style here and expressed my scenario in a quite natural language. As the comments are indicating the scenario is following the Arrange Act Assert (“AAA”) pattern.

With the Keyword “Given” I can create a test context (the objects I want to test). In this sample I created a list with 5 elements. With the keyword “When” I call a function which does something with my test context. In this case I want to remove the value 3. In the Assert section (keywords “It should” or “It shouldn’t”) I can give some observations, which should hold for my manipulated test context.

When I run this scenario via a NUnit runner (i am using TestDriven.Net) I get the following output:

Scenario: When removing an 3 from a small list it should not contain 3

– Given [1; 2; 3; 4; 5]
– When removing 3
=> It should not contain 3
=> It should contain 4
==> OK

Example 2 – Specifying a factorial function

If you implement factorial function the spec could look like this:

[<Scenario>]
let When_calculating_fac_5_it_should_equal_120() =
  Given 5
    |> When calculating factorial
    |> It should equal 120
    |> Verify    

[<Scenario>]
let When_calculating_fac_1_it_should_equal_1() =
  Given 1
    |> When calculating factorial
    |> It should equal 1
    |> Verify          

[<Scenario>]
let When_calculating_fac_0_it_should_equal_0() =
  Given 0
    |> When calculating factorial
    |> It should equal 1
    |> Verify

And the output of NaturalSpec would look like this:

Scenario: When calculating fac 0 it should equal 0

– Given 0
– When calculating factorial
=> It should equal 1
==> OK

Scenario: When calculating fac 1 it should equal 1

– Given 1
– When calculating factorial
=> It should equal 1
==> OK

Scenario: When calculating fac 5 it should equal 120

– Given 5
– When calculating factorial
=> It should equal 120
==> OK

Getting started

Of course you can use NaturalSpec to specify C# objects. I see my post "Using NaturalSpec to create a spec for C# projects" for a small sample.

You can download NaturalSpec at GoogleCode and follow the “Getting started” tutorial in order to write your first automatically testable spec.

I am very interested in your feedback. Do you like the syntax? What should I change? Do you consider using a spec tool like NaturalSpec?

Tags: , , , , , , , , , , ,