SharpDevelop Community

Get your problems solved!
Welcome to SharpDevelop Community Sign in | Join | Help
in Search

Matt Ward

August 2011 - Posts

  • SpecFlow Integration

    The SpecFlow team recently released version 1.7 and with it they included support for SharpDevelop 4.0. SpecFlow is an open source framework that you can use to do Behaviour Driven Development (BDD) on .NET. It allows you to bind business requirements to the code. Let us take a look at how SpecFlow integrates with SharpDevelop.

    Installation

    Download and install the following:

    1. SharpDevelop 4.0
    2. SpecFlow 1.7.0

    If SharpDevelop is installed first then the SpecFlow installer will detect SharpDevelop, as shown in the screenshot below.

    SpecFlow installer detecting SharpDevelop 4.0

    The installer will then add a set of SpecFlow templates to SharpDevelop. It will also install a SharpDevelop addin which you will need to register using the addin manager. To register the SpecFlow addin start SharpDevelop and from the Tools menu select AddIn Manager. This will open the AddIn Manager dialog.

    AddIn Manager dialog

    Click the Install AddIn button and browse to the SpecFlow installation folder. The default installation folder for SpecFlow is C:\Program Files\TechTalk\SpecFlow. In this folder find the TechTalk.SpecFlow.SharpDevelop4Integration.addin file, select it and click the Open button. The SpecFlow addin should then be displayed in the AddIn Manager dialog.

    SpecFlow addin installed in SharpDevelop 4.0

    Restart SharpDevelop so the SpecFlow addin is loaded and is ready to be used.

    Now let us take a look at how to use SpecFlow with SharpDevelop.

    Using SpecFlow

    Here we will follow the workflow that is shown on the SpecFlow web site. This workflow looks at creating a bowling game using SpecFlow.

    In SharpDevelop create a new C# class library project called Bowling. Right click the project just created and select Add New Item. In the New File dialog open the SpecFlow category and select the SpecFlow Feature template. Change the filename to be ScoreCalculation.feature. Click the Create button to save the file.

    SpecFlow feature file template in New File Dialog

    Replace the existing text in the feature file created with the text shown below.

    Feature: Score Calculation 
     In order to know my performance 
     As a player 
     I want the system to calculate my total score 
     
    Scenario: Gutter Game 
     Given a new bowling game 
     When all of my balls are landing in the gutter 
     Then my total score should be 0 
     
    Scenario: All Strikes 
     Given a new bowling game 
     When all of my rolls are strikes 
     Then my total score should be 300

    This is the specification for one part of the game. It is written in a language called Gherkin which gives you a user friendly way to specify a set of behaviours that your application should have. More information about the Gherkin language can be found on the Gherkin wiki.

    Now select this feature file in the Projects window, right click and select Properties. In the file properties change the Custom Tool to be SpecFlowSingleFileGenerator.

    SpecFlowSingleFileGenerator custom tool set in file properties

    Now every time you save the feature file a new file will be auto-generated.

    ScoreCalculation.feature.cs generated file.

    If you open this generated file you will see that it contains a class that has two NUnit tests.

    Generated file with NUnit tests.

    To run the unit tests you will need to add a reference to NUnit and SpecFlow to the project. In the Projects window, right click your project and select Add Reference. Select the .NET Assembly Browser tab and browse to the NUnit.Framework.dll file that can be found in the SharpDevelop folder C:\Program Files\SharpDevelop\4.0\bin\Tools\NUnit and add that file as a reference. Do the same for the TechTalk.SpecFlow.dll file which can be found in the C:\Program Files\TechTalk\SpecFlow folder.

    Now create a new file called BowlingSteps.cs and copy the following code into it.

    using System; 
    using NUnit.Framework; 
    using TechTalk.SpecFlow; 
     
    namespace Bowling 
    { 
     
     [Binding] 
     public class BowlingSteps 
     { 
      private Game _game; 
     
      [Given(@"a new bowling game")] 
      public void GivenANewBowlingGame() 
      { 
       _game = new Game(); 
      } 
     
      [When(@"all of my balls are landing in the gutter")] 
      public void WhenAllOfMyBallsAreLandingInTheGutter() 
      { 
       for (int i = 0; i < 20; i++) 
       { 
        _game.Roll(0); 
       } 
      } 
     
      [When(@"all of my rolls are strikes")] 
      public void WhenAllOfMyRollsAreStrikes() 
      { 
       for (int i = 0; i < 12; i++) 
       { 
        _game.Roll(10); 
       } 
      } 
     
      [Then(@"my total score should be (\d+)")] 
      public void ThenMyTotalScoreShouldBe(int score) 
      { 
       Assert.AreEqual(score, _game.Score); 
      } 
     
      [When(@"I roll (\d+)")] 
      public void WhenIRoll(int pins) 
      { 
       _game.Roll(pins); 
      } 
     
      [When(@"I roll (\d+) and (\d+)")] 
      public void WhenIRoll(int pins1, int pins2) 
      { 
       _game.Roll(pins1); 
       _game.Roll(pins2); 
      }  
     
      [When(@"I roll (\d+) times (\d+) and (\d+)")] 
      public void WhenIRollSeveralTimes2(int rollCount, int pins1, int pins2) 
      { 
       for (int i = 0; i < rollCount; i++) 
       { 
        _game.Roll(pins1); 
        _game.Roll(pins2); 
       } 
      } 
     
      [When(@"I roll the following series:(.*)")] 
      public void WhenIRollTheFollowingSeries(string series) 
      { 
       foreach (var roll in series.Trim().Split(',')) 
       { 
        _game.Roll(int.Parse(roll)); 
       } 
      } 
     
      [When(@"I roll")] 
      public void WhenIRoll(Table rolls) 
      { 
       foreach (var row in rolls.Rows) 
       { 
        _game.Roll(int.Parse(row["Pins"])); 
       } 
      } 
     } 
    }

    The BowlingSteps.cs file shown above implements the scenarios defined in the feature file and will be used by the unit tests to verify the implementation works as expected.

    The only bit that is missing is the code that implements the bowling game logic. Create a file called Game.cs and copy the code shown into it.

    namespace Bowling 
    { 
     public class Game 
     { 
      public void Roll(int i) 
      {     
      } 
       
      public int Score {  
       get { return -1; } 
      } 
     } 
    } 
    

    The Game.cs file contains the main Game class that implements the logic that we are going to test. Currently this code is incorrect so we are expecting the unit tests to fail.

    In the Unit Tests window (View | Tools | Unit Tests) click the Run all tests toolbar button. All the tests should fail as shown below.

    All specflow unit tests failed.

    Now we need to fix the tests. The GutterGame test is the easiest to get working. Edit the Game class and change the Score property so it returns 0.

    namespace Bowling 
    { 
     public class Game 
     { 
      public void Roll(int i) 
      { 
      } 
       
      public int Score {  
       get { return 0; } 
      } 
     } 
    }

    Now when you run the unit tests again the GutterGame test will pass.

    SpecFlow gutter game unit test passes

    The next step would be to change the Game class so the AllStrikes unit test will pass. Then you could define more scenarios in feature files to cover more functionality that you want the bowling game to have. Then you would go through the process just described until you have a working solution that meets all the requirements. These steps are not shown here but hopefully you get the idea.

    We have looked at how SpecFlow integrates with SharpDevelop and walked through the process of defining a set of scenarios that our application should have, creating unit tests to check the scenarios are implemented correctly and finally implementing the application logic so the unit tests pass.

    Further Information

    More information on SpecFlow can be found on the SpecFlow web site and on the SpecFlow GitHub wiki.

    Posted Aug 09 2011, 08:23 PM by MattWard with no comments
    Filed under:
Powered by Community Server (Commercial Edition), by Telligent Systems
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.