SpecFlow, BDD for the .NET World

SpecFlow, BDD for the .NET World

Given you have an interest in Behaviour Driven Development (BDD)
And you’re the king of.NET
When setting up your BDD supporting framework
Then SpecFlow is for you

The above is the Gherkin syntax used within the SpecFlow testing framework, which supports BDD. This same Gherkin syntax is also used in other BDD supporting frameworks such as Cucumber, Cucumber-jvm and JBehave.

Before diving in to SpecFlow, I feel it’s useful to have a quick paragraph on what Behavior Driven Development is. Advanced apologies if this is teaching you how to suck eggs!

So here we go: https://en.wikipedia.org/wiki/Behavior-driven_development – Paragraph complete.

was a tough one.


So, what is SpecFlow

SpecFlow is a .NET, BDD supporting test framework that allows us to write meaningful tests in plain English. When I say, “meaningful tests in plain English”, this refers to the BDD element, meaning tests written can be understood by everyone, no matter what your technical ability is. This is why BDD is so popular in an Agile world, as every member of the scrum team can read and understand what the tests are trying to achieve.


How does it work

I see SpecFlow being split down in to two areas (Feature Files & Step Definition), with both areas being split down even further.


Feature Files

These always start with the story description E.g.

Feature: Learning SpecFlow 

As a tester learning SpecFlow
I'm going to write loads of Feature File scenarios for the Act. Consultancy website
So I can become an expert in this chosen field

The purpose of these story description is to provide a high-level overview of what your feature tests are trying to achieve.

Next you have your scenario.

Scenario: Navigating to the Act. Consultancy website homepage.

This sets the tone for your individual test, while ensuring it keeps in-line with the overall objective of the feature. If you wanted to write a test for Act. Consultancy Blog page, this would form part of a brand-new Feature File dedicated to the Blog page. It would not form part of this Feature File which is dedicated for writing tests for the Homepage.

You would most likely have multiple scenarios for each Feature File (however, this may not always be the case). For Example:

》Scenario: For my second SpecFlow test, I am going to review the content of the Act. Consultancy homepage.

》Scenario: For my third SpecFlow test, I am going to confirm the partner information is displayed on the homepage

》Scenario: For my fourth SpecFlow test, I am going to test whether each partner has a photograph on the Homepage.

And so on….


Finally, you have your scenario steps.

This is where you start to use the Gherkin Syntax of Given, When, Then (as exampled at the very beginning of this blog post).

The scenarios steps sit beneath each scenario and form the body of the test.

The Given step

Sets a past action, or the current state of a process (Given I have done xyz, or Given I am on webpage xyz)

The When step

Sets the action you’re about to take that will produce some sort of result (When I click on this submit button, or When I logout of this application)

The Then step

This is the assertion, confirming the result triggered by the When step. (Then I receive confirmation my application has been submitted, or, Then I am directed to a new screen containing text confirming I have logged out).

Of course, so far, the Feature Files scenarios I’ve been describing are of a basic level. SpecFlow is a powerful tool, and a lot of that power is contained within the Feature Files. They can be used to pass through table information, parameters and much more. I have added such examples at the end of this blog.


Step Definitions

This is where your “coding” commences.  Step Definitions have a direct link to the Feature Files. Not at the hierarchy Feature File level, but at the Scenario Steps. This allows for particular words, tables etc which form part of a Scenario Step, to be passed through to the Step Definition as a parameter, so it can then form part of the code to complete that Scenario Step.

When coding your Step Definition, its best practice to continue to have BDD in your mind, this is because Step Definitions are not supposed to be code heavy. All the heavy code sits a layer or two beneath, within Helper files. This adds extra benefit when it comes to the maintenance of your tests, as you may have multiple Step Definitions re-use the same helper file. Therefore, you’d only have to maintain that single helper file, rather than all the individual Step Definitions that use it.

I kind of see the Step Definition as an orchestration tool which pulls together all the test data and code required to achieve its desired results


How does SpecFlow differ from Cucumber, Cucumber-jvm and JBehave.

The truth is, there is not much difference. Cucumber was designed for tests written in Ruby, Jbehave is designed for JAVA, and so is Cucumber-JVM, Specflow is a ‘port’ of Cucumber designed for .NET.

They all use the same Syntax of Gherkin. But, one noticeable difference is the way parameters are passed through to the Step Definition. e.g. SpecFlow shows (.*) where as JBehave shows $stringName


In Conclusion

If you want to adopt BDD in a .Net world, then the powerful framework of SpecFlow is the way forward.


Examples on the next page

Feature File Examples

Below are examples of what you can do with feature files


Backgound

A “Background” is one of those functions that’s I don’t feel is often used. The reason I say this, is because it can only be used when you’re sure all scenarios within a feature file follow the same, identical steps prior to testing the assertion. If a single scenario within a feature file takes a different path to all other scenarios in order to test its assertion, then the Background functionality can’t be used.

An example of a Background is below:

Background: Initial generic step for all tests within this feature file to follow
Given I want all tests within this feature file to start from the same screen
And that starting screen is at the half-way point of an end-to-end process

# When you use a Background at the top of the feature file
# Then all tests will commence by running this “Background” steps
NOTE: When and Tshen are commented out because you shouldn’t use assertions as part of the Background, assertions are the expected results of an individual test


Basic “Given|When|Then” Test

The below is an example of a very basic test scenario.

 @Test
Scenario: Can navigate to the posts page of the Act. Consulting Website
       Given I have navigated to the Act. Consulting Website
       When I click on the posts tab
       Then I am directed to the posts tab of the Act. Consulting Website

MultilineText string 

A multiline Text string allows the user to add a large string as part of the assertion (“Then” Step), a string that can spread across multiple line.

This is useful for when you want to compare actual on-screen text, to the expected assertion text. E.g

@Test
Scenario: The posts page of the Act. Consulting website displays the correct heading Text
       Given I have navigated to the Act. Consulting website
       When I click on the posts tab
       Then I see the correct heading Text
       """
       Posts
       """

When converted to the Step Definition, the assertion above looks like:

 [Then(@"I see the correct heading Text")]
public void ThenISeeTheCorrectHeadingText(string multilineText)
{
Driver.Instance.PageSource.Contains(multilineText).Equals(true)
}

“string multilineText” contains the string “NEWS” from the feature test, so you can write code to compare this against the actual on-screen web-browser text (using the OnScreenTextReader code under the C# section below).


Feature Step Parameter

Within a feature file test, any of the “GIVEN | WHEN | THEN” steps can have a parameter. These are treated as strings, and the text within the parameter is the string content. E.g.

Example below:

@Test
Scenario: The politics page of the BBC News website displays the correct heading Text
       Given I have navigated to the Act. Consulting Website
       When I click on the Posts tab
       Then I see the correct heading Text

As you can see form the above, “Posts” is a different colour and now in Italic font. This means it has been turned into a string parameter with “Politics” being the required string content.

This could just as easily be any of the following:

       When I click on the Home tab

       When I click on the The Team tab

       When I click on the Contact us tab

The StepDefinition for this step looks like:

[When(@"I click on the (.*) tab")]
public void WhenIClickOnThePoliticsTab(string tabParam)
{
  Driver.Instance.FindElement(By.Id("#" + tabParam)).Click();
}

With regards to the (.*) and the “string tabParam” within the StepDefinition, I had to define these myself. Once built, they are reflected within the feature file test, turning the “key” word grey and italic.

Using this type of step means you can re-use this code multiple times, knowing that the text you type into the parameter, is the string used in the StepDefinition.


Solution Outline

Solution Outline allows you to run the same tests multiple times but with different parameters. For example, if you have 4 different parameters, then that would be classed as 5 different tests. See below

@Test
Scenario Outline: The posts page of the Act. Consulting website displays the correct heading Text
       Given I have navigated to the Act. Consulting website
       When I click on the <WebPage> tab
       Then I see the correct heading Text
Examples:
       |WebPage     |
       | Home        |
       | The Team    |
       | Posts       |
       | Contact us  |

The StepDefinition for this step looks like:

[When(@"I click on the (.*) tab")]
public void WhenIClickOnThePoliticsTab(string tabParam)
{
Driver.Instance.FindElement(By.Id("#" + tabParam)).Click();
}

With regards to the (.*) and the “string tabParam” within the StepDefinition, I had to define these myself. Once built, they are reflected within the feature file test, turning the “key” word grey and italic.

Using the Scenario Outline means instead of writing 4 sets of different feature tests, I’ve just written the 1 test that will run 4 times, with the “examples” table defining the parameter of each different test (in order).

NOTE: with the Solution Outline, you can also have multiple parameters for each test. E.g.

@Test
Scenario Outline: The politics page of the BBC News website displays the correct heading Text
       Given I have navigated to the BBC New website
When I click on the <WebPage> <Param2> <Param3> tab
       Then I see the correct heading Text
Examples:
       |WebPage     | Param2      | Param3      |
       | Home        | Value 2     | Value 3     |
       | The Team    | Value 2     | Value 3     |
       | Posts       | Value 2     | Value 3     |
       | Contact us  | Value 2     | Value 3     |

This is still classed as 4 tests, but with each tests having 3 parameters.


Tables

Sometimes, you may want to check the content of two values. One way of doing this is by creating a feature test table containing the expected values, so you can then compare these against the expected values, see below:

@Test
Scenario: Table columns contains the correct values
Given I have a table
Then the table column values are correct
       | Column One | Column Two | Column Three |
       | Value A1   | Value B1   | Value C1     |
       | Value A2   | Value B2   | Value C2     |
       | Value A3   | Value B4   | Value C3     |

Even though there are 3 rows within this table, unlike Solution Outline, this is not classed as 3 different tests. This is 1 tests with 3 values in column 1.

StepDefinition will look like the following:

[Then(@"the table column values are correct")]
public void ThenTheTableColumnValuesAreCorrect(Table table)
{
ArrayList Expected_ColumnOne = new ArrayList();
 foreach (var entry in table.Rows)
    {
       Expected_ColumnOne.Add(entry["Column One"]);
   }
 
ArrayList Expected_ColumnTwo = new ArrayList();
foreach (var entry in table.Rows)
   {
       Expected_ColumnTwo.Add(entry["Column Two"]);
  }
 
ArrayList Expected_ColumnThree = new ArrayList();
  foreach (var entry in table.Rows)
   {
       Expected_ColumnThree.Add(entry["Column Three"]);
  }
}

“Table table” is pre-populated.

The above StepDefinition looks a bit untidy, to make it look better, you can put this code in to a helper file which is called by the StepDefinition.

Helper file code for Column One only:

public static ArrayList FeatureFile_Expected_Stage(Table table)
{
ArrayList Expected_ColumnOne = new ArrayList();
  foreach (var entry in table.Rows)
{
Expected_ olumnOne.Add(entry["Column One"]);
}
   return Expected_ColumnOne;
}

StepDefinition code for Column One only:

[Then(@"the table column values are correct")]
public void ThenTheTableColumnValuesAreCorrect(Table table)
{
ArrayList Expected_ColumnOne = Helper.FeatureFile_Expected_Stage(table);
}

Leave a Reply

Your email address will not be published. Required fields are marked *