0% found this document useful (0 votes)
43 views38 pages

SpecFlow & Gherkin Testing Guide

SpecFlow is a tool that allows business analysts and non-technical users to define automated acceptance tests in a business-readable format. It bridges communication between domain experts and developers. The module provided an overview of SpecFlow, acceptance testing, and how SpecFlow fits into test-driven development approaches. It described installing the Visual Studio SpecFlow extension and creating a new project with a feature file to begin defining acceptance tests.

Uploaded by

Gkfb AC
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views38 pages

SpecFlow & Gherkin Testing Guide

SpecFlow is a tool that allows business analysts and non-technical users to define automated acceptance tests in a business-readable format. It bridges communication between domain experts and developers. The module provided an overview of SpecFlow, acceptance testing, and how SpecFlow fits into test-driven development approaches. It described installing the Visual Studio SpecFlow extension and creating a new project with a feature file to begin defining acceptance tests.

Uploaded by

Gkfb AC
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Overview and Installation

Module Overview

Hi I'm Jason Roberts from Pluralsight, welcome to this course on Automated Acceptance Testing with

SpecFlow and Gherkin. In this module we'll get an overview of what SpecFlow and Gherkin are and

how we can use them to define acceptance tests that we can automate. In this module we'll get an

overview of the SpecFlow tool itself. We'll discuss acceptance tests in general and some of their

characteristics. We'll learn how we can broadly categorize testing into business facing and technology

facing tests. We'll see how SpecFlow can be used in test-first approaches. And we'll look at the

structure of SpecFlow tests and we'll breakdown the different components. We'll look at how we can

install the Visual Studio IDE integration for the SpecFlow tooling. And finally we'll create a new project in

Visual Studio and add our first feature file to it.

What is SpecFlow?

So what is SpecFlow? SpecFlow is an open-source tool for bridging the communication gap between

domain experts and developers. It essentially allows non-technical people, such as product owners or

business analysts, to write acceptance tests for the system that we're developing. SpecFlow enables

these acceptance tests to then be automated and allows them to be executed against the system we're

building to verify that the acceptance tests pass. The project site for SpecFlow is at www. specflow. org.

What is an Acceptance Test?

What is an acceptance test? An acceptance test enables us to validate that we're building the right

system and that the system contains the right features that are required by the users, the business, or

the product owner. Acceptance tests are usually from the point of view of the business or the user or the

customer point of view, but we may have a proxy for these people in the role of the product

owner. Because acceptance tests are from the point of view of the business, they should be written in a
non-technical format. This format can have some formatting rules to enable it to be translated

into automatable steps, but it should be an easy to understand and use format. Acceptance tests, when

executed, are a pass or fail affair there's no middle ground. The acceptance tests help to document

what the system should do, they may compliment other documentation or they may form the sole

specification of what the system should do. It depends on the team and project. When acceptance

tests are automated they can become what's described as living documentation. For example, if the

system is documented in a Word document or Excel spreadsheet it's easy for them to become out of

sync with the actual system and how it behaves. By automating acceptance tests we create a link

between the specification and the actual implementation. If the acceptance tests are changed or the

system is changed in an unexpected way, then we can execute our documentation, the acceptance

tests, to verify that things still work as expected. And acceptance tests, when executed, usually exercise

a vertical slice through the system. So in contrast to unit testing where we're just concerned with testing

a single class or integration testing where we might be testing groups of classes and components,

acceptance tests can touch all of the different layers in a system. From the lower data layers right up

through the business layer and even to the UI layer. If the acceptance tests are created collaboratively

and then used to drive what's actually being built, it can enable the whole team to have a

shared understanding of exactly what's required of the system. Acceptance tests can help to define

what done means so the scenarios that make up a feature, once they all pass we can say that the

feature is complete and can be marked as done.

Business Facing Tests

Conceptually one way of grouping tests is to divide them between those tests that face the business

and those tests which face the technology. So acceptance tests can be thought of as business facing

tests in that they're designed to be written and read by business people. So this could include product

owners, users, and business analysts, but it's also a good idea to get the whole team involved

when creating acceptance tests and this includes the testers and developers. Technology facing tests
on the other hand are generally only created by developers and these tests test the

technology implementation. So here we're talking about things like unit and integration tests and

processes such as test driven development. Martin Fowler defines business facing tests as "A test

that's intended to be used as an aid to communicating with the non-programming members of a

development team such as customers, users, business analysts, and the like". Whereas our technology

facing tests are really written by and for developers. It would be extremely hard for non-programming

members of the team to make sense of unit tests.

SpecFlow is just A Tool

Ultimately SpecFlow is just a tool. We can use it in a number of different context, whether it be

acceptance test driven development, behavior driven development, some kind of general agile

process, conceptually it could even be used in a waterfall scenario, but this is certainly not what it's

aimed at. And also hybrids of all these approaches. SpecFlow itself doesn't impose any specific

software development lifecycle process.

Use in Test-first Approaches

When SpecFlow is used in test-first approaches we first start off by discussing with the team what the

system should do next. And it's important at this point to get the business or users or product owners

involved in the conversation. Once we've had this conversation we can then write the tests in

SpecFlow. Once we've written the test we then start to write our code. Once we've written our code we

execute the SpecFlow tests to see if they pass. If the tests don't pass we continue writing code until

they do. Once the tests pass we can then define what the system should do next. And go around the

circle again.

SpecFlow Structure
So let's take a look at the SpecFlow structure itself. First off we have our Visual Studio integration and

we'll see in just a moment how we can install this. So with SpecFlow we start at the top with a feature

file. So a feature could be something like the addition feature in a calculator. Once we have our feature

file we define a number of scenarios that describe individual usages within this feature. So for calculator

this could be a scenario where two positive numbers were added and another scenario could be

where two negative numbers were added. Logically a scenario consists of a number of steps and in

general terms these describe the state before, the action during, and the expected state afterwards.

Sometimes in unit testing this is described as a range act assert, but when we come to discuss the

Gherkin syntax, in the next module, we'll discuss this further. For each individual step in the scenario we

can write the actual test code that interacts with the system under test. And to create this test code we

make use of a testing framework. So this could be something such as NUnit. The testing framework

such as NUnit can integrate with our test runner in Visual Studio and allow us to make use of the testing

frameworks assert methods to determine ultimately whether a scenario has passed or failed. The

SpecFlow Visual Studio integration, amongst other things, allows us to run tests right from the scenario

level without having to locate the individual test code and execute the tests from that level. The feature

file and its scenarios are written in a business readable language and again we'll cover the Gherkin

language in module 2.

Installing in Visual Studio and Creating A Feature File

So let's see now how we can install the SpecFlow Visual Studio integration. We'll then go and create

our first feature file. We can install the SpecFlow integration by opening the Extensions and Updates

window and searching on line for SpecFlow. So here we're going to install the SpecFlow extension and

hit Install and I'll just close this window. And we just need to restart Visual Studio for the install

to complete. So let's go ahead and do that now. So the first thing we need to do is create a new class

library project in this empty solution. So let's go ahead and do this we'll add a new project and we've

got Class Library project and we'll go ahead and call this Foo. specs. So let's go ahead and click OK.
And we'll just delete the auto added class 1 from the solution. So now we have our class library

project to hold our features, we can go and add our first feature file. So we'll go to Add New Item and

notice now that we've got these new SpecFlow items that we can add. So we'll start here by selecting

SpecFlow Feature File and we'll just give it a name AwesomeFeature and we'll just hit Add. So when

we add a feature we get a template that we can use to start writing our feature and this is written in the

Gherkin language which we're going to be looking at in module 2. So notice here in our Solution

Explorer we've got our Feature file now and inside this Feature file we can define a number of

Scenarios to create our acceptance criteria for this feature. Once we've created our Scenarios each

of these steps within the Scenario we can automate and verify that the system behaves as expected.

Module Summary

So that brings us to the end of module 1. In this module we gained an overview of SpecFlow itself. We

learned what acceptance tests are and some of their benefits. We saw how we can group tests into

business facing and technology facing tests. And how we can use SpecFlow in test-first approaches.

We learned about the basic structure of SpecFlow tests and we saw how we can install the

Visual Studio extension for SpecFlow. And how to create a new feature file. Join me in module 2 when

we'll explore the Gherkin language itself.

The Gherkin Language

Module Overview

Hi welcome back to module 2. In this module we'll be looking more closely at the Gherkin language that

we use to write our acceptance tests. In this module we'll be learning how we define features

and scenarios within those features. How we use the given, when, then steps to flush out our individual

scenarios. We'll look at how we can classify scenarios and features by using tags. And how we

can comment out individual lines within our features. We'll look how we can define tabular data to be

passed to the automation for our steps. And how we can use scenario outlines to create data driven
scenarios. Finally we'll look at backgrounds and how we can use them to provide common setup for all

of the scenarios in a given feature file. So let's get started by diving into features.

What is Gherkin?

So what is Gherkin? Gherkin is a business readable domain specific language. It represents tests in a

natural language that the business can understand as opposed to code that only programmers

can understand. It's a line-oriented language where new lines represent distinct elements and it uses

indentation to create a sense of structure. Gherkin has a number of keywords such as feature and

scenario. And these keywords are localized in over 40 spoken languages, for example

French, Bulgarian, and Japanese, this means that the Gherkin tests don't have to be written in English.

Features

Features are the top level grouping in Gherkin. A feature contains one or more scenarios and we'll look

at scenarios in just a moment. Features group or contain logically related test scenarios. Each feature

file represents a small discreet feature of the system. You wouldn't, for example, create a single feature

file that has scenarios for everything the system did. Feature files start with the keyword feature. This is

followed by a feature name or a short terse description of the feature. Following the feature name we

can optionally add our own free text description to help describe what the feature covers and the

scenarios contained within. So if we were creating a feature to represent brushing of teeth we'd

start with the feature keyword and in this case the name of the feature is Brush Teeth. And here we

followed this with an optional text description that we create by indenting, either using spaces or tabs,

a number of lines representing the description. So here the text Brushing teeth is good because it helps

keep them clean, doesn't have anything to do with automation, it's purely some additional information

that we can give to the reader. So our feature free text description can pretty much follow any format or

no format that we desire, but there's a number of standard formats that are often used. The first follows

the format as a, I want, so that. So we could rewrite the free text description in our Brush Teeth feature
using this format. So first off we start with the role or the person and this is the As a human. Next

we have the I want part, so here we're saying I want to brush my teeth. And finally the outcome or value

that we desire, here we're saying So that they stay pain free. And this format puts the role or the person

first. So we can describe this type of description as role or person centric. Some people have criticized

this format in that the value that we're trying to get doesn't appear until the end. So an alternative to this

format is the in order to, as a, I want format. So we can rewrite the previous as In order to stay pain

free As a human I want to brush my teeth. And in this format we put the value in the first line. So we can

describe this as value centric. Again you don't have to use these formats, but they can help to solidify

exactly what the feature is covering. And again you don't have to, you can use any kind of text that you

feel is useful.

Scenarios

So once we've created our feature file we then start to add scenarios to it. Scenarios are concrete

examples of the expected behavior of the system we're testing. Each scenario describes a particular

situation and use of the feature. Each scenario should be independent and isolated from the

other scenarios. So this means that we should be able to run any given scenario at any time and it

should always produce the same result, pass or fail. For example, we shouldn't depend on another

scenario having just been run for the next scenario to pass. Scenarios can represent the happy paths of

the feature so these are the normal expected usages where everything is okay. Scenarios can also

represent what happens when certain error conditions are met. And we can also have our

scenarios represent those edge cases of things that don't occur very often but things that are important

to us. We mark the start of a scenario by using the scenario keyword. We then follow this by the title of

our scenario. For example, a scenario representing a successful brushing of teeth would be

represented like this, the scenario keyword with a code on followed by our title.

Steps - Given, When, Then


Each of our scenarios consist of a number of steps. We can think about these steps as falling into one

of three overall phases. In the first phase we set up the initial state of the system. This is where we get it

ready to perform the specific actions that we want to test. Next we actually perform those actions

against the system. Once we've performed one or more actions we check that the end state of

the system, after we've performed these actions, is as expected. In Gherkin these phases map to the

following keywords. In the setup phase we use the given keyword to create our setup steps. When we

perform actions we use the when keyword in our action steps and for our end state we use the then

keyword. So if we look at this successful brushing scenario we can add our steps to it. So first off in our

setup phase we have our givens and notice these are indented. So here we're saying in our setup

phase we're saying that there's toothpaste on the brush and that the mouth is open, given that these

things are true we next come to our action steps. So here we use the when keyword. When the

back teeth are brushed, when the front teeth are brushed, then the teeth look clean and then the mouth

feels fresh and then the braces aren't damaged. So the thens form our third phase where we check that

the resulting state of the system is as expected. So in this scenario we've got multiple givens, whens,

and thens, but notice that it doesn't really read particularly naturally, so we can try and improve this

scenario by changing it and adding the and keyword. So now our setup phase, the given, reads a bit

more naturally because we've used the and keyword. Given there is toothpaste on the brush and the

mouth is open. We can also use the and keyword in our second phase. So here we're saying when the

back teeth are brushed and the front teeth are brushed, again this reads more naturally than having two

when lines. Finally we can use the and keyword and also the but keyword to make our third phase, the

then phase, read more naturally. We're now saying then the teeth look clean and the mouth feels fresh,

but the braces aren't damaged. So here we've still got our three conceptual phases, but we're making

use of the and and but keywords to improve the readability. And we can go one step further and use

indentation to further improve the readability.

Tags
The Gherkin language gives us the idea of tags. They allow us to mark our features and scenarios with

arbitrary tags. Tags can map to categories in the unit test framework we're using to perform

the automation and allow us to execute only those scenarios that have a specified tag. Tags can be

applied at the feature level or on individual scenarios. If we apply a tag to the feature each of the

scenarios within that feature inherit that tag. Scenarios and features can have multiple tags and we

specify a tag by prefixing it with the @ symbol. The ignore tag is a special case in that it enables us

to temporarily remove tests from being executed. So to mark this successful brushing scenario with the

smoke test tag we simply proceed it with @smoketest. There's a number of potential usages for tags.

We can use them to group features into supersets of features, we could mark certain tests as being

more important than others, we could differentiate between slow running and fast running tests,

we could mark certain tests as being works in progress, or we could use tags to indicate how often tests

should be executed. For example, weekly, daily, or hourly and we could also mark tests for example

by specifying @humanexecuted to exclude them from automation and to indicate that the specific

scenarios, for whatever reason, have to be executed manually by a human tester.

Demo: Applying Tags

So let's have a look at tags in action. So here we've just got a Feature file and we've got three

Scenarios. In our Visual Studio Test Explorer we're currently in the Class view. And here we can see

our three scenarios underneath our Feature file. So let's go ahead and switch to this Traits view and

here we can see our three Scenarios and they have no traits applied. When we talk about traits we're

talking about a similar concept to categories in unit tests. So we can start to categorize these scenarios

by using tags. So let's start with Scenario A and let's say we want to add this to the important category.

If we build now we can see that we've got our Scenario A now belonging to the important Category and

our scenario B and C as not belonging to any category. So let's go ahead and mark Scenario B

as being a fast executing test. And Scenario C as being a slow executing test. Again we rebuild and we

can see now our tests in their different categories. We can add multiple tags to a scenario, so Scenario
A is now important and fast. If we build we can see now that Scenario A is both part of the fast category

and the important category. We can apply tags to the feature itself so let's mark the entire feature as a

work in progress and build. We can now see that all of the scenarios in this feature have inherited the

work in progress tag. So now our Scenario A has three tags applied. These two at its scenario level and

this one inherited from the feature. And we can see this here. Scenario A belongs to the fast, important,

and work in progress categories.

Demo: Commenting Lines

If we need to we can add comment lines by prefixing the line with the hash symbol. So for example let's

just comment out the important tag by applying a hash and notice that it goes green. And say

for example that we wanted to comment out the When line here and just replace it with another one. If

we wanted to we could also comment out to the tag at the feature level or just add arbitrary comments

between these two scenarios. (Typing)

Data Tables in Steps

We can use data tables in individual scenario steps. Data tables allow us to pass tabular data to the

underlying automation step. And they're useful for specifying larger datasets rather than having multiple

individual steps to specify the data. So this scenario here Given I have paste and brush and water when

the back teeth are brushed then the teeth look clean, we could rewrite this using a data table to specify

the given tools we need. So here we've replaced the multiple given steps with a data table we're saying

given I have the following tools paste, brush, and water, when the back teeth are brushed then the teeth

look clean. So to use a data table in a step we add a code on to the end of the step and then we create

a table in text by using the vertical pipe symbol. So here we've created a table with a single column

and three data rows, paste, brush, water with a column name of tool name. When we come to write the

automation step for this given we get a parameter passed to the automation step containing this

data table. We can then use the items in this data table in our automation.
Data-Driven Scenario Outlines

Whereas data tables allow us to pass tabular data to an individual scenario step. Scenario outlines

allow us to execute the same scenario over and over again each time using a different set of test data.

So rather than writing many scenarios with only small variations in data we can create one scenario

outline and then specify the data to be input to this scenario outline when each execution occurs. To

define a scenario outline we use the scenario outline keyword with a colon followed by the name. So

here we're creating a scenario outline called teeth whiteness. When we create a scenario outline we still

use our given, when, and thens and optionally our ands and buts, but this time we can define place

holders for the data that we want to execute the steps with. So here we're saying given I'm using some

kind of brand of toothpaste, when I brush for so many minutes, then the teeth look so much percent

white. So we're not specifying actual values, we're specifying place holders inside these angle brackets.

Now we've created our scenario outline we need to be able to specify the data to be substituted

into these place holders. And we do this by using the examples keyword. Similar to data tables, we

create a table using vertical pipes, but this time our column headers map to place holders in our

steps. Each individual row in the table represents a single execution of our scenario outline. So here

we've got three data rows which means this scenario will get executed three times. The first time with a

brand of Brand X, mins of 1, and percent of 80. The second time with Brand Y and its associated data

and the third time with Brand Z and its associated data.

Backgrounds

Gherkin provides us with the concept of backgrounds. A background provides context to the scenarios

within a given feature. The steps within a background are executed before each and every scenario

runs. To create a background we use the background keyword, followed by colon, and then

the individual steps that make up the background. So here our background states that given I have

teeth and I have some toothpaste. The two steps within this background get executed before

the successful brushing scenario executes and before the toothpaste runs out scenario executes and it
would also execute before other scenarios if we added them. So using backgrounds we can reduce

some duplication in the individual scenarios within a feature. We just have to be careful when we're

using backgrounds that the background doesn't get too large and unreadable and that the things in

a background are relatable to the business reader.

Module Summary

So that brings us to the end of module 2. In this module we learned about Gherkin features and

scenarios and how to write scenarios using given, when, and then steps. We also saw how the but and

and steps can help us create more naturally readable scenarios. We saw how we can categorize

features and scenarios using arbitrary tags and how we can add comments to our feature files. We saw

how we can define data tables to be passed to the automation for individual steps. And how we can use

scenario outlines to create data driven scenarios. Finally we looked at backgrounds and how we can

use them to provide common setup steps for each of the scenarios in a given feature file. Join me in

module 3 when we'll see how we can hookup all of our steps in our scenarios to actual code

automation.

Coding The Automation Steps

Module Overview

Hi welcome back to module 3. In this module we'll be learning how the steps in a scenario bind to the

C# methods where we can actually perform our automation. In this module we'll learn about the

relevant NuGet packages that we need to install to utilize NUnits in SpecFlow. We'll look at two different

styles of binding step definitions to scenario steps and we'll see how we can set a default step definition

style when we generate our step definition files. We'll see what happens when we add a new step and

when we delete an existing step. We'll see how we can execute scenarios and debug individual step

definitions. We'll see how we can share step definitions between scenarios and how we can use

parameterized step definitions to promote reusability and reduce maintenance overhead. We'll


learn how when using a data table in a step how the data is passed through to the step definition and

our code. And we'll look at how scenario outline steps map to step definitions. Finally we'll look at how

we share scenario context and data between the individual steps that make up a scenario.

Installing The Required NuGet Packages

So the first thing we need to do is install the relevant NuGet packages. So we've already got the

SpecFlow extension installed and enabled. And now we have to add in the NuGet packages that we

need. So if we just do a search for SpecFlow we can see that we get a number of results. So if we look

at this SpecFlow NUnit package we can see that this depends on the SpecFlow package and the NUnit

package. So by installing this one SpecFlow. NUnit package we'll get everything we need to start writing

our automation. If we look at our installed packages we can see now that we've got NUnit and this is

the testing framework we'll be using in our automation. We then have the SpecFlow NUnit and the

SpecFlow itself package. So all of these packages combined with the extension that we've already

installed give us everything we need to start creating our automation.

Step Definition Binding

Now we have our NuGet packages installed and we've written our first Feature file with our first

Scenario. We now need to create the automation for each of the steps within the Scenario. So notice

here that each of these steps is highlighted in purple and this indicates that there's currently no

automation set up for these steps. When we're working with SpecFlow and Gherkin we need a way to

translate these natural language expressions into automatable and executable code. In SpecFlow

there's a concept of binding. Binding is essentially the hooking up of individual steps to individual pieces

of automation code. And we can see in the Test Explorer here that we don't currently have any tests in

our solution. If we take a look at our Solution Explorer we can see we have our. feature file here and if

we expand this down we can see we have this generated C# file. If we have a look at this we can see

that it's designer generated code and ordinarily we wouldn't change any of this. This code
essentially hooks up our natural language sentences to the SpecFlow framework and the

underlying unit testing framework that we're using. So in this case it's NUnit. And we can see NUnit in

use in this generated code through these attributes, but we don't need to worry too much about

this generated code. So now we need to create a class that contains methods that map to each of

these scenario steps. To do this we right-click and we head down to Generate Step Definitions. When

we open this dialog we're given the choice to select which steps we want to generate step definitions

for. So we're just going to leave this as all of them ticked, we get to choose the class name that we

want to generate, and we have a number of options for the style of binding. So by default it's this

Regular expressions in attributes style. And we'll come back to this in just a moment. For now I'm

just going to click Generate and I'm just going to leave the file name the same. If we have a look in our

Solution Explorer now we can see we've got our new class file. If we have a look at this we can see

that it contains methods for each of our steps in our scenario. So the first

step GivenThereIsToothpasteOnTheBrush, Given there is toothpaste on the brush and the mouth is

open, The mouth is open and notice here that this is mapped to the conceptual Given phase. We don't

have a separate and attribute and the same is true for the but attribute. The braces aren't damaged

appears as a Then attribute and also notice now that in our Feature file the steps have changed from

purple to white. And this indicates that there's a binding between the natural language and some code.

If we were to go and delete one of these bindings, so let's delete

the GivenThereIsToothpasteOnTheBrush, just save that, and if we head back to our Feature file now

notice that this step has reverted back to purple. And that's because no binding is available for this step.

So let's go ahead and remove this step definitions file and everything goes back to purple and we'll

right-click again, choose Generate Step Definitions, but this time we'll choose from the style dropdown

the Method name underscores option. If we click Generate now just OK the file name head back to

Solution Explorer and to our step definitions and this time we can see a different style here. The

attributes are now simply Given, When, or Then and the method name has been generated using

underscores between each word. Let's go back to the original style, (Typing) so this is the default

Regular expressions in attributes style (Typing) and notice here that we've got our text specified in the
attribute itself as well as in the method name and again in the actual original scenario step. So say

we change one of these steps, let's change the When the back teeth are brushed step and we'll change

this to read When all the back teeth are brushed. And immediately this changes to purple to indicate

that there's no matching step definition that can be bound to. So to restore this binding we head back to

our step definitions file and we can just change the attribute value here When all the back teeth are

brushed, Save this. And head back to our Feature file. Notice now that this step has gone from purple

back to white. Because the binding between this scenario step and the step definition has been

restored. And in this case it's because we're using the regular expression style, but notice here the

method name we haven't changed. And that's because it's the text in here that creates the binding. We

could actually name this method anything. So when we're working with the regular expression style it's

possible for the actual method name to quickly become out of sync with the actual binding and original

step text. And of course we could change this manually, but this can create some maintenance

overhead. So let's see what happens in this scenario if we use the underscore style. So I'll just

close this and we'll go and delete it and we'll regenerate these step definitions and this time we'll choose

the underscore style as before and hit Generate. And hit Save. So this time we don't have any text in

our attributes and the method names include underscores. And if we go back to our Feature file

everything is white which means we have matching step definitions for each of these steps. So let's

change this back to just when the back teeth are brushed. Again we notice it goes purple and to fix this

we head back but rather than having to change a string into the attribute and also the method name.

We can just change the method name now. So here we can remove the all, we Save this, head back to

our Feature file. And now the mapping has been restored and the step has changed back to white. So

we'll be using the method name underscore style for the rest of this course.

Setting The Default step Definition Style

We can specify the default style of binding by changing the app config. So by default when we hit

Generate Step Definitions it defaults to the Regular expressions in attributes style. So to change this


default we can open the app. config and we can add an additional line in the SpecFlow section. So here

we've added this trace element and we've set the step definition skeleton style to use method name

underscores. And if you want to know more about this configuration head to this link here. And this will

take you to the SpecFlow documentation. So now we've specified our Method name underscore to be

the default format, if we hit Save and we just get a warning here and SpecFlow's offering to regenerate

our feature files if required, so let's just hit Yes for now. And let's head back to our Feature and now

when we choose Generate Step Definitions we can see that the style now defaults to Method

name underscores, as opposed to the default Regular expressions in attributes. And notice here there's

a third option to use Method name Pascal case instead of underscores, but again we're going to stick to

the Method name underscores format for this course.

Adding New Steps

Let's take a look at what happens now when we add a new step to our scenario. So here we've got our

scenario and we've got our step definitions. So let's go and change this and let's just add an extra And

to the Given section. So it goes purple, so it means we need a step definition for this scenario step. So if

we go and right-click and choose Generate Step Definitions as before we only get the choice of one

because this is the only one that's not bound to a step definition. If we click Generate and we'll keep this

as BrushingOfTeethSteps. cs we get a warning that we're overriding it and if we click Yes and just hit

Yes because this is open in Visual Studio. If we go and have a look at our steps file now we can see

that we've only got one step definition. And if we look in the Feature all of the other lines have turned

purple. And that's because we've overridden the previous step definitions file and now it only

contains this step. So how do we add a new step definition? Well let's reset this, we'll delete this file,

we'll comment out this extra line for a moment and we'll go and generate everything again. Hit Save.

And now we can see our original step definitions. So let's uncomment this line. So we need to create an

individual step definition for this line. And we'll add it to our existing step definitions. So to do this we

head back to our Scenario, go to Generate Step Definitions, again we only get a single choice, but this
time instead of choosing Generate we'll choose Copy methods to clipboard. Now if we go back to our

step definitions we can paste what we've just copied to the clipboard. So here we can see our x_y_z

line in our step definitions now. And if we head back we can see that once we save this step definitions

file our line goes back to white. So that's how we can add a new step definition when we add a new

step to our scenario.

Deleting Steps

If we want to completely remove a scenario step we simply delete it from the scenario, so we've just

removed the x_y_z step and we can just hit Save and that's all we really have to do. However,

there's also the matching step definition and if we leave this here it won't cause any problems, but we

have to be careful that we don't create a maintenance problem in the future. So assuming this

step definition isn't shared with multiple scenarios, and we'll have a look at this concept later in the

module, we can simply go ahead and delete the step definition. One small tip is that when we're

deleting or editing a scenario step if we're working with a lot of scenarios and features, we can use a

handy navigation shortcut before we delete or change something. So for example, say we wanted to

delete And the front teeth are brushed, we could first right-click and choose Go To Step Definition. This

will then open the step definition file in the right place. So we can just delete the step definition, head

back to our Feature, and delete the line.

Running and Debugging Scenarios and step Definitions

So once we've got our scenarios and our step definitions how do we actually execute our scenarios and

kickoff the test automation? The first thing to check is that if you haven't already got it installed in

Extensions and Updates you need to check that you've got the NUnit test adaptor for Visual Studio

installed. Because we're using NUnit as our underlying framework and we're using the Visual Studio

Test Explorer we need to install that extension in order for Visual Studios Test Explorer to understand

NUnit. So to run a scenario we can simply right-click on it and choose either Run SpecFlow Scenarios
or Debug SpecFlow Scenarios. Let's hit Run. If we have a look at our test output for the

successful brushing scenario we can see that we get a message telling us that one or more

step definitions are not implemented yet, but we have actually generated our step definitions here. The

reason we're getting this message is because when we generate the step definitions the generation

adds the ScenarioContext. Current. Pending line. And this instructs SpecFlow that although we've

generated our step definitions we haven't actually implemented any code in them just yet. If we needed

to debug one of these step definitions we simply place a breakpoint in the step definition and we

can right-click and choose Debug SpecFlow Scenarios instead of Run Scenarios. So let's click this and

we can see now that our breakpoint has been hit in our Given_there_is_toothpaste_on_the_brush step

definition. In addition to right-clicking on the scenario and running it from there we can also use the

Test Explorer to search for specific scenarios to execute. So here we've just got one scenario, but we

could run it by right-clicking and hitting Run or Debug Selected Tests. So that's how we can execute a

scenario by either right-clicking inside the Feature file or by using the Visual Studio Test Explorer to

initiate the test run.

Sharing step Definitions

Our step definitions can be shared between multiple scenarios. So here we've got our successful

brushing scenario and all of the steps have matching step definitions. So let's go and add another

scenario. So notice here that the When x and then z lines are showing as purple because they don't

have any matching step definitions, but this given line There is toothpaste on the brush is showing as

white. Even though for this new scenario we haven't generated any steps. And that's because

there's already a step definition for this Given step. So if we right-click and choose Go To Step

Definition we can see that there is in fact a step definition for this line. If we navigate to the Given in

the first scenario we can see that it goes to the same place. So this Given step definition currently will

execute for both this scenario step and this scenario step. This sharing of matching step

definitions means that we can make use of code reuse in our automation steps, but this does, however,
mean that when we're changing step definitions we just have to be aware that if they're shared they will

affect multiple scenarios.

Parameterization to Promote step Definition Reusability

Another way we can reduce maintenance overhead is to use parameterized step definitions. So let's

say we had this scenario here and we want to modify it to specify the amount of toothpaste on

the brush. So let's say here Given there is 1 gram of toothpaste on the brush, so we need to go and

update our step definition binding. So Given_there_is_1_gram_of_toothpaste_on_the_brush let's Save

this and just double-check that it's gone white. And let's say now that we also want another scenario

with 2 grams of toothpaste. So let's take a copy of this and let's just call it Successful brushing 2. And

we'll change this to 2 grams of toothpaste on the brush. So we can go and copy this step definition and

change this to 2 grams. Again we'll Save it and just double-check here that everything's okay, which it

is. So now we've got two scenarios where the only difference is in this Given line. So although all of

these step definitions will be reused, we've got two step definitions for these Givens that only differ in

the data, ie the number of grams of toothpaste that's on the brush. So here in our step definitions we've

got two steps that when we come to write the actual automation will be extremely similar. So we can

reduce this code duplication in our step definitions by making use of parameterization in our

step definitions. So let's go and delete these two Given step definitions. Hit Save and head back and

notice now that we've got our two Givens that are not bound. If we right-click and go to Generate

Step Definitions we can get a preview, but notice that in this preview it's only going to generate a single

Given for the two selected Givens that we've specified here. So let's just close this preview and Copy

the methods to the clipboard and head back to our step definitions and let's just paste this in. So we've

only pasted in one Given, if we Save it and head back to the Feature notice now that both of our Givens

have turned white. Also the number in these Givens has changed to an italicized grayed out color. So

why is this? Well if we have a look at the generated step definition we can see now that in place of the

actual number of grams we have this P0, we also have a parameter that's now been added to our step
definition, also called p0. So let's go and put a breakpoint here and let's debug our first successful

brushing scenario. And our breakpoint gets hit and if we have a look at the value of this parameter we

can see that it's a 1 representing the 1 gram from our scenario step. If we stop this and instead

debug successful brushing 2 once our breakpoint gets hit we can have a look at our parameter value

and this time we've got the number 2 to represent 2 grams from the second scenario. So in this way

we've created a parameterized step definition that we can share between multiple scenarios. If we want

to we can go and rename this parameter so let's call it grams of toothpaste, or just grams. If we debug

this now we can see that we get our value for grams of toothpaste and we can also improve the

readability of the step by replacing this P0 with something more meaningful. To do this we just

specify something in capital letters. So let's just call it GRAMS. Again if we debug this we can see that

we get our grams of toothpaste. If we go and change the values in the Feature, so let's say 11 and

22, and just choose one of these to debug notice now that we get our new value for grams. So that's

how we can use parameterized step definitions to reduce the code duplication in our step definitions

where we have the same basic step definition but it only varies by data values.

Multiple and String params in A Single step Definition

We can also pass multiple parameters in a single step definition and also specify both strings and

numbers. So let's change this Given and we'll add two parameters. So again we'll add so many grams

of toothpaste and we'll also add another parameter to specify the brand of toothpaste. So let's just make

up a brand called Brand X. So Given there is 2 grams of Brand X toothpaste on the brush. So we can

go and edit our step definition now. So Given_there_is, (Typing) and again we use upper case to

denote the parameters, so Given_there_is_GRAMS_grams_of_BRAND_toothpaste_on_the_brush we

now have to add the method parameters. So the first one is a number, so we'll say int grams to match

the uppercase grams here and also we'll add a string parameter called brand to match the brand

parameter here. And these parameters in the method definition have to be in the same order as they

appear in the method name. Hence we've got GRAMS and grams first and BRAND and brand second.
If we Save this and head back to our Feature we now see that our Given step has gone back to white

and now we've got two parameters signified by the italics and the gray 2 and Brand X. So let's debug

this and we'll see what parameters we get passed. So let's go across here to our parameters and

for grams we can see we've got 2 and for brand we've got Brand X. We can go here and change this to

say 22 and Brand Y, debug the test again check our parameters and we have 22 grams and Brand Y.

Creating A step Definition with A Data Table

We saw in the previous module how we can specify data tables in Gherkin. So here in this Given step

we've specified a data table containing two columns, ToolName and ToolQuality, and we have three

data rows within the table. So how do we access these data items in our step definition? If we look at

our step definition here we can see that we've got this parameter of type table and this is a SpecFlow

table class. And we can use this table object to get at the table data in our step definition here. So to get

the firstToolName here we're using indexes, so we're saying the first row and the first column in the first

row. And here we're saying again the first row, but the second column. As well as using indexes for

the columns we can also specify the name of the column. So here we're saying the secondToolName is

at row 1, these being 0 based indexes. And the column is called ToolName. The secondToolQuality

again we're on the second row in the table, and we're looking for the column called ToolQuality. There's

a couple of other methods on this table object to do things such as rename columns and there's

also the useful ContainsColumn method which we can use to test for the existence of a column with a

specified name. So here we're saying does the table contain a column called Color, which it doesn't.

So let's go ahead and debug this test and we'll have a look at this table structure. So we have access to

a collection of Headers, so if we expand this we can see we've got the headers or the columns

of ToolName and ToolQuality. And we also have this Rows property and we can drill down into this, see

each of the table row objects. Each table row object has a collection of keys and values and again

we can just expand this down and we can see we've got ToolName paste and ToolQuality medium. So

let's have a look at our variables here. The first ToolName we've got paste and Quality medium, so this
maps to paste and medium here. And the second ToolName of brush and the second ToolQuality of

high, so again this maps to brush and high. If we look at our IsToolColorColumnSpecified we can see

that we've got false as expected. So that's how we can specify a data table in Gherkin for a Given step

and how we can access the rows and columns by adding a table parameter to our step definition.

Scenario Outline step Definitions

So let's take a look at scenario outlines in use. So here we've got our scenario outline from module 2,

we have three parameters, brand, mins, and percent and these map to the columns here. So

notice we've got these quote marks around our string type and these other things are numbers. So let's

go ahead and generate our step definitions, but this time I'm going to start with the Regular

expression style and we'll see why in a just a moment. So let's generate this and let's go and have a

look at our step definitions. So notice that we're using the Regular expression style and for our Given

step for our string it's added our string parameter as expected. So we can put a breakpoint here and we

can debug one of these tests and if we look at our parameter 0 we can see that we get Brand X as

expected. So let's delete these step definitions and let's now generate them using the Method name

underscores style. Let's go and look at our step definitions now so we're not using the

Regular expression style this time. And let's do the same as before, add a breakpoint and then debug

the test. And let's have a look at our parameter value again, but notice this time we've got this additional

quote. We can see that we've got Brand X followed by this quote, which is clearly wrong. So we'll Close

this and stop debugging and let's go back to our Features. And we have a hint here that something is

not quite right. The opening quote is white but the closing quote is gray. When we're not choosing the

Regular expression style we need to remove these quotes. If we debug the test again and check our

string parameter now we can see that we've got Brand X without the additional quote. If we look at our

Feature file we can see that we don't have any gray items now, so this is a hint to us that everything is

as expected. And as with parameters before we can go and make this a bit more readable. We change

this to Brand and the corresponding parameter also to Brand and we could do the same things for these
When and Then parameters as well. So let's just double-check everything is working as expected. So

for this first example in the scenario outline we have our Brand X, if we debug the next one we have our

Brand Y, and if we debug the final one we get our Brand Z. So that's how we can map scenario outline

examples to individual step parameters.

Sharing and Maintaining State Between step Definitions

Because in SpecFlow each of the individual steps in a scenario map to a separate method in our step

definitions sometimes we need to be able to pass data between individual step definitions. One way

we can do this is to use the ScenarioContext. Current and we can use this as a dictionary to add keys

and values to the currently executing scenario context. So when each scenario executes we get a

new scenario context and we can add things to it. So here the key is brand name and the value that

we're storing is the brand that's passed through as a parameter. The next step that gets executed is this

When I brush for so many minutes step. And even though this is a separately executing step we can

retrieve the brand name from the scenario context by specifying as an indexer the key that we added

here. So let's see this in action. We'll debug this test and if we check our brandName variable we can

see that we got Brand X that we stored in the previous step. And we can see this for the other tests.

This time Brand Y was stored. If all our step definitions exist in the same class instead of using the

scenario context we can create private fields. So here we could simply create a field and rather than

use the scenario context we could simply say that we're setting the internal field to the value of this

parameter passed in in this step. And then we could simply use this underscore brand field in this step

here. So just to illustrate, if we run this now we can see that our brand field in the class is set to Brand

Y. So this private field approach is fine if all our steps are within the same class, but because matching

step definitions don't have to be all in the same class, so a scenario could have two steps. One

step could be bound to a step definition in one class and another to a step definition in a different class

we can't always use this approach. And that's when storing things in ScenarioContext. Current is more

flexible.
Module Summary

So that brings us to the end of module 3. In this module we learned how to install the relevant NuGet

packages to get NUnit and SpecFlow working together. We saw the regular expression style of binding

and the method underscore style of binding. We learned how to change the app config to change the

default step definition style. We saw what happens when we add and delete steps. And we saw how we

can execute scenarios and debug individual steps within those scenarios. We saw how a step definition

can be shared between multiple scenarios and how we can parameterize step definitions so we can

reuse them. We saw how to access the data items in a data table when we pass it to a step definition.

And we also saw how when we're using data driven scenario outlines how the data maps to our step

definition parameters. And finally we learned a couple of methods of sharing data between scenario

steps.

Testing and Automating a Website with SpecFlow and


WatiN

Module Overview

Welcome back to Module 4 Testing and Automating a Website with SpecFlow and WatiN. Even though

we're using WatiN in this module to perform the browser automation. If you're using another framework

for your automation such as Selenium or Microsoft Coded UI the processes we'll go through in this

module such as refactoring our scenarios and step definitions apply regardless of which automation

framework you're using. So in this module first off we're going to get an overview of the website that

we're going to be writing our tests for. We'll get a brief introduction to the WatiN automation framework

and we'll go ahead and write a scenario for the password strength feature of the website. We'll then go

and create our automation code for the password strength scenario and also look at how we can

refactor this to improve the code base. We'll look at how we can use WatiN hooks to dispose of

the browser instance. We'll then look how we can refactor our password strength scenario into a

scenario outline to reduce duplication in our feature file. We'll see how we can further simplify our
feature files by introducing a background and finally we'll see how we can refactor our step definitions

into other classes so we can organize them in a more logical fashion.

Overview of The Website under Test

So before we get into writing our first scenario let's have a quick look at the demo website that we're

going to create our acceptance tests for. If I just run it we default to this Sign Up page and this is the

feature that we're going to be working with. So this Sign Up page is where a new user would go to

create a new account on this website. So we can type in a username, an email address, and we can hit

Register. And we get some simple validation errors if there's a problem so here the passwords don't

match and we have an invalid email address. So if we fix these two things (Typing) and correct

the password, when we click Register if all of the validation passes then we're taken to this

RegistrationComplete page and we get our username displayed to us. Also notice that we've got this

password strength, so let's go ahead now and create a feature file and our first scenario.

A brief Introduction to WatiN

WatiN is an open-source framework that allows us to automate Internet Explorer browsers. For example

to click buttons and type text into text boxes and you can find out more about WatiN at watin.

org. Alternatives to WatiN also include Selenium and Microsoft's Coded UI. If you want to learn more

about Selenium or Microsoft Coded UI check out the other great courses on Pluralsight. com. We'll be

getting a brief overview of WatiN in just a moment, but if you want to go into more depth check out my

Automated Testing: End to End course. So let's have a look at some WatiN code in action. So here

we've got a NUnit test and the first thing we do is we create a new instance of this WatiN IE class. And

here we're wrapping it in a using statement so that when the instance gets disposed any unmanaged

resources will be cleaned up for us. By default when we lose this IE object the corresponding Internet

Explorer window will also be closed. And for demo purposes I've set this AutoClose property to false so

that our Internet Explorer window stays open and we can see what's happening. Also for demo
purposes I'm making a call to this BringToFrontForDemo extension method that I created just so we

ensure that IE is in the foreground and we can see what's happening when we execute this test.

So now we've got our WatiN object, two enablers to automate the Internet Explorer window, we can

start to work with it. So first off we can navigate to a specific URL by calling the GoTo method. So

here I'm opening up this Register page on my local machine. Once this navigation is complete we can

then work with elements on the page. So for example to find a text field with a given ID we say ie.

TextField and one of the ways we can locate this is to try and find it by the HTML Id. So here we're

saying give me the text field with the Id of Password. When we locate this text field we're just assigning

it to a variable here. So once we've located an element on the page we can interact with it. So for

example with this text box we can use the TypeText method to simulate a user typing text. So here

we're simulating a user typing the words Hello World into this text box. We can work with other

HTML elements such as divs, spans, and buttons as well. So for example if we wanted to click a button

with an Id of DoRegister we'd say ie. Button locate it by its HTML Id and once we've located it, in this

case we're not assigning it to a variable, we're just directly calling its Click method. And this will simulate

a user actually clicking on this button in the browser. So let's go ahead and run this test and see WatiN

in action. So we quickly saw then how the string Hello World was typed into the password box and how

the Register Now button was clicked. And because we've got some validation errors here we've just got

the validation messages appearing here. So that's how we can create an instance of the WatiN IE class

and use it to navigate to a specific URL and then interact with the HTML elements that exist on the

page.

Writing The Password Strength Scenario

Let's go ahead now and create our feature file. So for example we can think of the feature that we're

working with as the new user registration feature. So first off let's go and create a feature file and we'll

call it NewUserRegistration. So let's remove this default scenario and just tidy things up. So first off

let's add some description of the feature in this free text section and we'll use the in order to as an I
want format. So let's start with In order to get access to the member only Features As a potential

new user I want to create an account. So let's add the first scenario to this Feature. So we'll call this

Scenario Password strength indicator and in this Scenario we'll be checking that when the user

types different lengths of password that we get the correct password strength indicated to them. So let's

start with our Given, so we can say Given I'm on the registration page, When I enter a password of

Pass, Then the password strength indicator should read Poor. We could also apply a tag to our

Scenario or our Feature to indicate that it belongs to a superset of logical features. So here we can

describe this Scenario as belonging to the authentication superset. So this would enable us, for

example, to run all scenarios related to authentication, so this could also include things like logging into

the site and resetting passwords.

Writing Automation for The Password Strength Scenario

So now we have our Feature file and our first Scenario, let's go ahead and create the initial version of

our automation with WatiN. So first off let's generate our step definitions and I've already set this project

to use the default for underscores. So here's our step definitions. So our first

step Given_I_m_on_the_registration_page we need to use WatiN to navigate IE to the correct page. So

first off let's go and install WatiN from NuGet. And here we'll install the WatiN package. And just Close

this and we'll add a using statement to WatiN. Core and we'll just remove this pending line here. So the

first thing we need to do is create a new IE object, but this time we can't create it with a using because

we don't want to dispose the IE instance as we need to use it in later steps. So first off let's just create

the instance and here we're using an overload of the constructor that allows us to specify the starting

URL. So here we're just going to the register page. And as in the WatiN overview I'm just going to make

a call to the BringToFrontForDemo extension method so we can see what's going on in

Internet Explorer. And I'm just going to include this extension method in our project. So let's just build

this and we've just got a build error as I haven't included the namespace for our extension method.

So let's just grab this namespace and add it here. Now we can build and notice we get our
PasswordStrengthIndicatorTest for our scenario here. I'm just going to change the view in Test Explorer

to the project view so we can just group all of our scenarios differently from our overview of WatiN test

that we used earlier. So let's go ahead and execute this first test. And we want to see if Internet

Explorer opens correctly and it's on the right page. So we've got an error here when we tried to execute

the test. If we have a look at it we can see that it's making reference to this Interop. SHDocView and

that's because when we use WatiN we have to edit this reference and change the Embed

Interop Types property from True to False. And we can just build to make sure there's no errors and we

can try and run our test again. Notice that the test has failed again but for a different reason.

When we're using WatiN to automate Internet Explorer our tests need to execute in the single threaded

apartment threading model. So if we head to our AssemblyInfo we can change this by adding the

RequiresSTA attribute to our assembly. And this is an attribute that comes from the NUnit Framework.

This attribute instructs NUnit to execute tests using a single threaded apartment model. So let's close

this and build and now when we run our test we should see Internet Explorer open at the correct page.

And it does. So here we have our page Register. aspx loaded in Internet Explorer. So if we come back

to our automation steps, because we need to use this ie instance in our other steps we need

somewhere to store it. So we can use our scenario context to do this. Here we're adding our ie instance

to the ScenarioContext. Current with a key of Browser. Our next step is to enter the password of Pass

into the password text field. So first off we need to get a reference to the ie instance stored in

our ScenarioContext from the previous step. Next we want to locate the correct text box that represents

the password, so we're just using the FindById method and we're going to type the string Pass into it.

So notice here that we're just hard coding Pass as opposed to using a parameter from the step

definition. And we're going to perform some refactoring's later in the module. Unfortunately there's a bug

in WatiN that sometimes prevents events from firing on our HTML elements. So when we type a

password into the password text box every time we press a key a JavaScript event fires that updates

the password strength, but when we're using WatiN to type the text this bug means that the key press

event in JavaScript isn't fired. So as a workaround for this we can use the Eval method of the ie object

to evaluate some JavaScript in the browser. We're using jQuery here to select the password box and
force the firing of the key press event. And we can just add a comment here to explain things. So let's

go ahead and execute this test now with our second step. And we can see that our password of Pass

has been typed into the password box and our password strength is indicated to us. The final step is to

actually check that the password strength indicator reads correctly. So we expect it to read Poor. So as

before we get a reference to our ie object and the next thing we need to do is read out the string for the

password strength. So here we're locating a Div with the Id of PasswordStrength and we're just getting

its InnerHtml and assigning this to the strength variable. So now we've got the password strength

that's being displayed in the browser, we need to make a NUnit assert to check that it's correct. So here

we're expecting the string Poor and passing the actual string. Now we're at the end of this scenario,

we can dispose of our ie instance, but before we do this we just want to set AutoClose to false so we

can see what's happened in the browser for demo purposes. So let's go ahead and execute this

complete scenario now and see what our result is, but first just let's quickly add the NUnit

framework using statement so we can access the assert method and now run. And we can see that our

password has been typed in as before and the password strength is displayed as before, but if we head

back to Visual Studio now we can see that our test has passed. And to prove this is working let's

change the Assert and run the test again. And let's check our test result. And we can see this time

it's failed because we expected xPoor but was actually Poor. So let's just fix this up and Save and just

double-check and our test now passes again.

Refactoring Password Strength Automation Code

Whilst we have our basic automation working now we can make some improvements to the actual code

and perform some refactoring. So notice in these subsequent steps each time we have to go and grab

the ie instance from the ScenarioContext. So we have some code duplication here that we can take

care of. Also whilst we've only got one step definition creating an ie instance at the moment, if we had

to manually create an ie instance in the first step definition of every scenario we had, this would also

create some code duplication. So let's see how we can start to refactor things. If we go to our Solution
Explorer and I've added this WebBrowser class to our test project. If we have a look at this we can see

that we've got a public static class called WebBrowser and we expose a current property of type IE.

When we access this property getter we first check that the scenario context doesn't contain a browser,

if it does then we just return it, but if it doesn't contain the browser key we go ahead and create a new

one. And for demo purposes we just tell it not to close and bring it to the foreground. Once we've

created our Internet Explorer object we then just go and add it to the ScenarioContext. So now we've

got this new WebBrowser class that will deal with the creation and storing of ie instance for our

ScenarioContext, let's go and refactor our existing steps. So first off we can get rid of this line. So in the

first step here we still need to navigate to the registration page and to do this we can access our

WebBrowser. Current property, which will give us our ie instance. And then on this ie instance we can

call the GoTo method which will navigate to our register page. We can also get rid of these two lines

because in our WebBrowser class we're already bringing Internet Explorer to the foreground. And we

also no longer need to store our browser manually in our ScenarioContext. Again the WebBrowser

class is taking care of this for us, so let's delete these and we can see already that our step

definition automation code is starting to look a lot simpler. So for

our When_I_enter_a_password_of_Pass step we can again get rid of this retrieval of the Internet

Explorer object and we can replace this local ie variable with a reference to WebBrowser. Current. And

the rest of it stays the same as before. We still need to handle the firing of this key press event, but

again we can just replace this ie with WebBrowser. Current. Let's go to our Then step, again

remove this and we can replace our ie reference with WebBrowser. Current. We keep our Assert the

same, we can also delete our AutoClose line and replace ie Dispose with WebBrowser. Current

Dispose. So let's build this to check there's no errors. And run this test now. And we can see

our automation in progress and we can see that in Visual Studio our test passed.

Using hooks to Dispose The Browser Instance


So we've made some improvements to our automation code, but we still have this WebBrowser.

Current Dispose in our last step of our step definitions. We don't really want to have to worry

about disposing the WebBrowser. Current ie instance in the end of every Then step that we write.

SpecFlow provides us with a number of hooks that we can use to help us out in this instance. If we take

a look at the SpecFlow documentation at specflow. org we can see we have these attributes. Before

and after test run, before and after feature, before and after scenario, before and after scenario block,

and before and after steps. So let's take a look at how we can use the before scenario and after

scenario hooks. So I've added this ScenarioBeforeAndAfter class. If we take a look at it we can see that

I've decorated this class with the SpecFlow binding attribute and this tells SpecFlow that it should look

inside this class for bindings including these hooks. So here we've got this BeforeScenario attribute

or we could use the shortened version of Before and we're just applying this to a static void method. So

this method will be executed before each and every scenario starts and also before each and every

data example in a scenario outline. Similarly the AfterScenario attribute means that this After method

will get executed after each scenario finishes executing. So in this method I've added a call

to WebBrowser. Current Dispose so this will mean that after every scenario finishes executing the ie

instance will be disposed of. So we can now head back to our steps and remove this dispose line here.

So I've got the breakpoint in this After method and let's go and debug this test. So we briefly saw

Internet Explorer open then, if we pop back to it we can see our automation has taken place, Pass has

been entered, and if we hop back to Visual Studio we can see that our breakpoint has been hit in our

After method. So we can just continue this. So that's how we can use the BeforeScenario and

AfterScenario attributes to execute code before each scenario executes and also after each scenario

has finished executing.

Refactoring into A Scenario Outline

So now we've got our first scenario automated for password strength, we need to add more scenarios

to cover the password strengths of not only Poor but Average and Awesome. So we could go and copy
this scenario and duplicate it another two times and then change our scenario steps to use parameters

for the password and for the expected strength, but in this instance a scenario outline is a better choice.

As it will result in less duplication in our Feature file. So let's go ahead and replace this scenario with

a scenario outline. So here we've replaced the password that we type in and also our expected strength

indicator. And we've got three examples here pass where we expect Poor, Password where we expect

Average, and long password where we expect Awesome. So we need to change our existing

step definitions for our When and Then lines to take account of these parameters that we need to pass

in. So let's start with this When line. So here we're going to add a parameter and rather than typing

this fixed string literal we'll now type the password that was passed to the step definition. Similarly for

our Then step definition we'll add a parameter and we'll just rename this existing strength parameter as

ActualStrength and our expected strength will now be the strength passed in to this step definition via

the parameter that's mapped here. So if we Save this and check our Feature file notice now that both

password and strength have changed to italics to indicate that they're mapped to our example

columns password and strength. So let's build this and we can see now we get our three scenario

examples and let's go ahead and run all three. So that's our three scenarios executed and we're just

leaving the Internet Explorer windows open again, but if we head back to Visual Studio we can see that

our three scenario examples were executed and they all passed. So that's an example of how we can

use scenario outlines and pass the data provided in the step definitions parameters via WatiN to the

browser.

Writing The Existing user Scenario

Let's now explore our second scenario. So here I've added a new Scenario for the username already in

use. So here we're saying Given I'm on the registration page, When I enter valid new user details,

But the username Mr. Awesome is already taken, When I try to proceed with registration, Then I should

see an error sorry that username is already in use. So notice here that I've chosen to use two When

lines. So I could have written this When I enter valid new user details, But the username Mr. Awesome
is already taken, And I try to proceed with registration, but I think having this second When instead of an

And makes the Scenario read a little better, but we could certainly use an And if we wanted to. Now

we've started to add additional Scenarios, we can move this tag that's currently only applicable to

this Scenario outline to the Feature level. And now all of the Scenarios within this Feature will inherit this

tag. So I've already implemented the step definitions for our username already in use scenario and

notice here that the first step definition, Given I'm on the registration page, is shared with the Scenario

outline above, but the remainder of this Scenario I've created new step definitions for. So let's check out

this When I enter valid new user details first. So this step affectively fills out our form with valid data.

And here I'm creating a random username by just grabbing the first 10 characters from a NewGuid. We

then type this random username into the UserName text field, we enter an EmailAddress and we enter

the Password and the ConfirmPassword. The next step But the username Mr. Awesome is already

taken we've got something extra going on here. So we've got a parameter for the username being

passed into this step definition and we're typing in this username into the UserName text field, but

notice we're doing the same thing here so there's a bit of duplication, but this means that we can reuse

this step definition anytime we need to enter valid new user details into the form. So when the

username name is already taken, because we're passing in variable data here we want to ensure that

the system has a user setup for this name. So that when we come down to check that the right

validation message is displayed we can be sure that the state of the system, ie the username exists, is

as expected before we try and perform the user registration. So we're calling this CreateUser method

on this test data class and this is a class that I've created. If we look at this CreateUser method for

demo purposes the website is hard coded to recognize the username Mr. Awesome as it being an

existing username, but obviously in a real system the users would be stored in some backend storage

system for example a database. So to ensure that this username exists we could either directly insert it

into the underlying user database table, we could go via the app service layer to create a user,

or alternatively we could do it through the UI. So the UI will be the slowest method here, the next

slowest will probably be the service layer, and the fastest will probably be the direct insert into

the database. So depending on the system you're building you'll have a number of different options that
may suite you. So once we've ensured that our username exists in the system we then go and override

the username in the web page. The next step is the When I try to proceed with registration. If we have a

look at this we can see here that we're simply clicking the button called DoRegister, but notice in the

Feature we don't actually say When I click the registration button. And this is because wherever

possible in our scenarios we want to try and be as user interface agnostic as possible. The final step

Then I should see an error. Here we're finding the list of validation errors with the Id of

ValidationErrorList and we're simply saying all of the text within this list check if it contains the message

passed through as a parameter to this step definition. And then we're simply asserting that this is true

and if it's not true we're providing a more helpful failure message. So here we're just saying that the

message was not found in validation errors. So let's execute this and see it in action. So our automation

has finished, let's go back and check that we got a passing test, which we did. And we can double-

check this is working by changing the error message here and executing it again. So now when the test

runs the error message that we see will be different from the error message that we expect to see. So

let's head back to Visual Studio and we can see now that our test has failed with our helpful message

that Sorry yyythat username is already in use not found in validation errors.

Refactoring Features to use Backgrounds

So now we've got a couple of Scenarios in our Feature file, we can start to think about if we can remove

any duplication from our Scenarios. If we have a look at our two Scenarios here we can see that we've

got this duplicated Given I'm on the registration page step. And if we look at the description of our

Feature it's likely that all of the Scenarios within this Feature file will start on the registration page. So

we'd have this Given I'm on the registration page step at the start of each one of our Scenarios, but

we can prevent this duplication by introducing a background to our Feature. So let's go ahead and do

that and we'll just grab the Given line here and add it as a background step. We can then remove it from

this Scenario as well and now the background for all of the Scenarios in this Feature states that Given

I'm on the registration page. If we build this there's no errors and we don't have to change any of our
step definitions even though we've moved this Given line to the background, it still maps to the same

step definition, which we can see here. So let's go ahead and execute our username already in use.

And we can see our Scenario executes the same as it did before. So when we use a background for

a Feature the background runs before each and every Scenario executes. And in the case of a

Scenario outline it will execute before each example in the Scenario outline, but the background will

execute after any Before hooks we've set up. So for example, our BeforeScenario hook here will be

executed first, followed by our background, and then the Scenario. So I've got a breakpoint here and a

breakpoint in this first Given step. If we go and debug this test we can see that the first breakpoint that's

hit is in our BeforeScenario hook, if we continue we can see now that we get our background

step executed next. And if we continue execution we'll get our Scenario executed. So that's how we can

use a background to execute one or more steps that are relevant and add context to each of the

Scenarios in our Feature.

Refactoring step Definitions into other Classes

As the number of Features and Scenarios in the test automation grows larger we might want to give

more thought about how our step definitions are organized. So at the minute we've got a single Feature

and a single matching step definition file. So in our Feature this Given I'm on the registration page step

we could consider this to be part of a logical set of navigation steps. So we could move its matching

step definition into a separate steps class. So let's go ahead and do this. So we'll Add a new Class and

we'll call it NavigationSteps. If we have a look at our existing steps we can now remove this Given and

paste it into our NavigationSteps file, but if we look here we also need to add the SpecFlow using and if

we look at our steps we can see that we use this Binding attribute of a public class, so we'll replicate this

in our NavigationSteps and we'll just build to check everything's okay, which it is. And if we go back to

our Feature now we can see that this Given line is still in white, which means SpecFlow is still finding a

matching step definition. It's just this time it's finding it in this NavigationSteps class. So if we run

our Scenario now we can see that it's executing as before, even though we've moved the step definition
into a separate class. If we were to remove this Binding attribute and build and check our Feature now

we can see that the Given step has changed to purple because SpecFlow can't find a matching step

definition. So let's just go and quickly add that back. So that's how we can start to organize our steps

into logical groupings inside our own classes as the number of scenarios grows over time.

Refactoring Browser Interaction into A Page Model

The final thing we're going to address in this module is the fact that in our step code here we have the

Ids of the controls we're interacting with duplicated throughout this code. So here we're finding the

TextFieldById of Password and again this Id is used in this Eval statement. We've got

the PasswordStrengthId, the UserName, Email, Password, ConfirmPassword Ids and so on. So we

have the Ids littered throughout our steps and as we continue to add Scenarios to our Feature this

proliferation of duplicated Ids will increase. So this is a problem because if the page we're

testing changes it's Ids for whatever reason then our automation will break. For example if the register

button changed its Id from DoRegister to Register then when we try and execute this step the button

would not be able to be located and so the button wouldn't be clicked and we'd get an error. So we

could go and create some constants either in this steps class or perhaps in a global Ids class, but a

better way is to create a class that models the registration page. So I've already created this class and

we can use this to abstract a way the underlying Ids of the page we want to automate. So the first thing

we do here is inherit from the WatiN page class and here we're just defining a number of constants to

represent the Ids of the controls we want to interact with. Then we simply create a property, in this case

for UserName, we create a get and a set and the get property locates the TextField with the Id specified

in our UserNameId constant and just returns its Text. And in the setter we're finding it and using

the TypeText method to enter text into the field. And we're doing a similar thing for the EmailAddress,

Password, ConfirmPassword, but when we get to PasswordStrength we don't have a setter because it's

just a Div that we're reading the content from. And similarly with the ValidationErrorListText we're

just returning the Text of the list. We also have a method called ClickRegisterButton and again this
decouples the actual button Id from our automation code. And in this example rather than creating a

constant we've just got the string literal. So the benefit of this approach is we've effectively decoupled

the Ids from our automation code and we'll see in a moment how it also makes our automation code

more readable. We can also do things like where we set the Password before in our automation step

we had to execute this Eval statement, but we can now encapsulate this in the setter for the

password property. So once we type the new password we call the Eval. So let's go ahead and look at

our steps. So I'm going to go and replace all of these steps with a version that I've modified to use this

new registration page class. So let's compare the old and the new. Before in

our When_I_enter_a_password step we had this WebBrowser. Current we're finding the Id and then

we're calling Eval to force a key press event, but now we're using these two lines. So when we create a

class that inherits from the WatiN Page object it allows us to use the Page method of the ie object to

interact with the current page that we're on in a strongly typed way. So here we're just saying we're on

the registration page and we represent this with a variable, in this case p. Once we have this page we

can use its properties and methods. So here we're just setting the Password property and when we do

this the setter will be called and the value we set the property to will be typed in to the password field.

And because we've encapsulated this Eval as well we no longer need to do this in our step definition.

The next step here, again we start by getting our page, but whereas before we had our actual strength

now we just set actualStrength to the read-only PasswordStrength property of the page. And let's just

go and add this Assert back in. For the When_I_enter_a_valid_new_user_details step we're still

creating our random UserName grabbing our page, but rather than these four lines here we replace

them with these four lines here. Again using the properties of the page. So you can see here that it's a

lot less cluttered than the original version. When we get down

to the When_I_try_to_proceed_with_registration step definition we simply call the ClickRegisterButton

method rather than having to find the button and click it ourselves. And in our error message step here

rather than having to perform this kind of work ourselves we just access the ValidationErrorListText

property and check it contains our message. So by using this registration page we've also isolated

the Ids of controls and improved the readability of our step definitions. So let's build this to check there's
no errors and let's go and run all of our scenarios to check that they still work. So we can see our

password strength scenarios executing and our existing username scenario, so let's head back

to Visual Studio and we can see that our tests still pass. So that's an example of how we can refactor

our step definition code to use a strongly typed page model. There's a couple of different

conceptual styles we can use when we represent pages, if you're interested in learning more about

these styles check out my Automated Testing: End to End course and have a look at the Functional UI

Testing Module. And in this module there's also more information about the WatiN framework.

Module Summary

So that brings us to the end of this module on SpecFlow and WatiN. In this module we saw an overview

of the website under test. We took a brief tour of the WatiN automation framework. And we wrote the

first password strength scenario. We then learned how to create our automation code for this scenario

and to refactor the code to improve readability and reduce duplication. We saw how we can use

hooks such as the before and after hooks to dispose of the browser instance. And we then refactored

our password strength scenario to use a scenario outline. We saw how we can use backgrounds to

further reduce duplication in our scenarios. And finally how we can move step definitions into other

classes that have the binding attribute applied.

You might also like