Search Here!

Tuesday, June 5, 2012

Behaviour Driven Development (BDD) in .Net using SpecFlow, Selenium RC and MS Test

BDD Using SpecFlow using .Net and MS TEST
I have been working on the Behaviour Driven Development (BDD) using SpecFlow for .Net and I felt it is fun. According to me, it is a Tester’s tool rather than a Developer’s tool and I felt it is worth sharing. Kindly refer the wiki for more theoretical info on BDD:

System Requirements:
Windows 7 as OS
Microsoft Visual Studio 2010 as IDE
SpecFlow as BDD tool for .Net
Selenium as a Test Automation Tool
Referencing the SpecFlow:
1.        Install the SpecFlow software on your machine.
2.        In Visual Studio, Go to the Project -> Add Reference menu item.
3.        When the Add Reference dialog appears, click on ‘Browse’ and navigate to C:\Program Files (x86)\TechTalk\SpecFlow and select TechTalk.SpecFlow.dll.
4.       Finally, the solution Explorer should look like this:

Consider a sample user story:

Feature: User Creation
   In order to Create user
  As a Workspace admin
   I want to create a w s user

Let me write a test scenario for the above story:
Scenario Create New User
 When I enter username in the username field
 And I enter password in the password field
And I press Login
 Then the response Page is Course Enrolment
 When I click the Create New User link
 User popup
 When I click the Save button
 Then It s
 And Enter the user details in Create Ne
would display successful message New user created successfully

Creating a new SpecFlow feature file:
1.        Context-click on the project name ‘SpecflowTest’ in the Solution Explorer
2.        Select Add -> New Item
3.        Select the ‘SpecFlow Feature File’ and save it as ‘_Feature.CreateNewUser.feature’
4.       Specflow creates a new file “ _Feature.CreateNewUser.feature ” and a designer file “ _Feature.CreateNewUser.feature.cs“. The default content of the Specflow file is in the Gherkin format.
5.        The default content of the file is as shown is below:
Feature: Addition
 In order to avoid silly mistakes
 As a math idiot
 I want to be told the sum of two numbers

Scenario: Add two numbers
 Given I have entered 50 into the calculator
 And I have entered 70 into the calculator
 When I press add
 Then the result should be 120 on the screen
6. Change the contents of the file to the new scenario as below and the Specflow generates a feature file ‘ _Feature.CreateNewUser.feature.cs ’:
Add Scenario according to your Feature:
Feature: User Creation
   In order to Create user
  As a Workspace admin
   I want to create a ws user

 Given I open frmLogin.aspx?mode=admin in the browser

Scenario Outline: Create New User
 When I enter  in the username field
 And I enter  in the password field
 And I press Login
 Then the response Page is Course Enrollment
  |username |password|
 When I click the Create New User link
 And Enter the user details in Create New User popup
  | Field          | Value                |
  | txtPassword    | password1            |
  | txtFirstName   | QA                   |
  | txtLastName    | BDD                  |
  | txtEmail       |        |
 When I click the Save button
 Then It should display successful message New user created successfully

1.        Rename the class ‘Class1.cs’ to ‘ _Feature.CreateNewUser.cs’.
2.        Context-click on the feature file ‘GoogleSearch.feature’ and select …… System generates a specification file ‘…..’ as shown below.

    public class CreateNewUserDefinitions : SeleniumStepsBase
        // Purpose: Creation Readonly Object(s)
        readonly NewUserPage _newUserPage = new NewUserPage();

        #region Locator
        private const string Button_Signin = "//button[@class='lgn_btn']";
        #endregion Locator

        // Purpose: Step Implemented To Enter Username For Ws Admin
        [When(@"I enter (.*) in the username field")]
        [Given(@"I enter (.*) in the username field")]
        public void EnterSomethingIntoThUsernameField(string username)
            // Purpose: Calling Method To Enter Username in Username Field For Ws Admin
            Selenium.Type("username", username);
            ScenarioContext.Current["username"] = username;

        // Purpose: Step Implemented To Enter password For Ws Admin
        [When(@"I enter (.*) in the password field")]
        [Given(@"I enter (.*) in the password field")]
        public void EnterSomethingIntoThePasswordField(string password)
            // Purpose: Selenium Method To Enter Password For Ws Admin in Password Field
            Selenium.Type("password", password);

        // Purpose: Step Implemented To Click on SignIn Button For Ws Admin
        [When("I press Login")]
        [Given("I press Login")]
        public void WhenIPressLogin()
            // Purpose: Selenium Method To Click on SignIn Button For Ws Admin

        // Purpose: Step Implemented To Click on 'Create New User' link in Ws
        [When(@"I click the Create New User link")]
        public void WhenIClickTheCreateNewUserLink()
            // Purpose: Calling Method To Click on 'Create New user' Link in Ws
            new AdminToolPage().StepClickCreateNewUserLinkWs();

        // Purpose: Step Implemented To Fill User Details
        [When(@"Enter the user details in Create New User popup")]
        public void WhenEnterTheUserDetailsInCreateNewUsePopup(Table table)
            // Purpose: Calling Method To Fill User Details
            foreach (var tableRow in table.Rows)
                Selenium.Type("//input[@id='" + tableRow["Field"] + "']", tableRow["Value"]);

        // Purpose: Step Implemented To Click on Save Button for User Creation
        [When(@"I click the Save button")]
        public void WhenIClickTheSaveButton()
            // Purpose: Calling Method To Click on Save Button for User Creation

        // Purpose: Step Implemented To Verify Success Message on User Creation in Ws
        [Then(@"It should display successful message New user created successfully")]
        public void ThenItShouldDisplaySuccessfulMessage()
            // Purpose: Caling Method To Verify Success Message on User Creation in Ws
            new AdminToolPage().StepSuccessMessageOnUserCreatedWs();
Creating a Static class for defining the browser selection:

    public static class SeleniumSupport
        private static ISelenium _selenium;

        // Purpose: Method Implemented To Get The Status of Test Scenario Web Seesion
        private static bool ReuseWebSession
            get { return ConfigurationManager.AppSettings["ReuseWebSession"] != "true"; }

        // Purpose: Action Taken by Before Test Scenario Starts
        public static void BeforeWebScenario()
            // Purpose: Starts Selenium Instance Before Test Scenario Starts

        // Purpose: Action Taken by After Test Scenario Ends
        public static void AfterWebScenario()
            // Purpose: Stop Selenium Instance After Test Scenario Ends
            if (ReuseWebSession)

            Assert.AreEqual(""ScenarioContext.Current.SeleniumErrors().ToString(), "Selenium verification errors");

        // Purpose: Method Implemented To Start Selenium Instance
        public static void StartSelenium()
            if (_selenium == null)
                if (Playback.IsInitialized)
                _selenium = new DefaultSelenium("localhost", 4444, ConfigurationManager.AppSettings["browser"], ConfigurationManager.AppSettings["browserUrl"]);
                catch (Exception e)
                   throw new Exception("Uanble To Start Selenium Server with Base Url: Please check your network settings.");


        // Purpose: Method Implemented To Stop Selenium Instance
        public static void StopSelenium()
            if (_selenium == null)

            catch (Exception ex)
                Debug.WriteLine(ex, "Selenium stop error");
            _selenium = null;
            Console.WriteLine("-> Selenium stopped");

    // Purpose: Method Implemented To Web Test Scenarios
    public static class ScenarioContextWebExtensions
        public static ISelenium Selenium(this ScenarioContext scenarioContext)
                var result = (ISelenium)ScenarioContext.Current["selenium"];
                return result;
            catch (Exception)
                throw new Exception("selenium is not started");

        // Purpose: Method Implemented To Get The Selenium Instance in Current Test Scenario
        public static bool IsSeleniumRunning(this ScenarioContext scenarioContext)
            return ScenarioContext.Current["selenium"] != null;

        // Purpose: Method Implemented To Set Selenium Property
        public static void SetSelenium(this ScenarioContext scenarioContext, ISelenium selenium)
            ScenarioContext.Current["selenium"] = selenium;
            ScenarioContext.Current["selenium-errors"] = new StringBuilder();
            ScenarioContext.Current["StepCounter"] = 0;

        // Purpose: Method Implemented To Handle Selenium Unexpected Error(s)
        public static StringBuilder SeleniumErrors(this ScenarioContext scenarioContext)
            var result = (StringBuilder)ScenarioContext.Current["selenium-errors"];
            Assert.IsNotNull(result, "selenium is not started");
            return result;
Executing the Tests: MS Test

For using MS Test, we need to add configuration in app.config
    <section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow"/>
    <language feature="en-US" />
    <unitTestProvider name="MsTest.2010" />
    <runtime detectAmbiguousMatches="true"
         missingOrPendingStepsOutcome="Inconclusive" />

    <trace traceSuccessfulSteps="true"
           minTracedDuration="0:0:0.1" />

No comments:

Post a Comment