Currently there is nothing difficult in code testing. There is a great amount of instruments (NUnit) and documentation. But when we speak about Web we shouldn’t forget about the Web-interface layer. We need to have our SpecFlow scenarios connected to Web-browser output. To achieve this goal, we can use Watin (Web Application Testing in .NET). It is used for testing applications in IE and Firefox. First of all using NuGet install Watin package into your project. Let’s imagine that we have Cookbook project for implementation. It’s a web-application that allows user to create, manage and share his recipes with other users. Each user can be registered in the system and afterwards logged in using this registration details. User can create, edit and delete recipes. Each recipe includes ingredients, which can be also added during creation of the recipe. All recipes should be listed on the main page for user. To make restatement of the problem more exact, let’s append a few user stories. I’ve written very simple implementation of this task with the use of MVC4. Below you can see main page
And this is the page with recipe’s details:
Let’s start with testing. We create .feature file in the test project. And our first test will be as follows:
@Recipes
Scenario: Login
Given I am on the "Login" page
When I have entered my credentials
| user | password |
| user | 123456 |
And I have pressed "Log in" button
Then I should be on "Index" page
And I should see the text "Hello, user!"
Add [assembly: RequiresSTA]after declaration of all dependencies [1]. Now by using pre-conditions initiate browser opening before each scenario and it’s closing afterwards. Property to store reference to Browser will be:
private IE Browser { get; set; }
and two methods BeforeScenario and AfterScenario are:
[BeforeScenario]
public void BeforeScenario()
{
Browser = new IE();
}
[AfterScenario]
public void AfterScenario()
{
Browser.Close();
}
We are ready. Now we are writing implementation for generated steps. Watin allows us to find components (TextFields, Tables, Images and so on) using their parameters (Value, Text, Class …). Page navigation is also possible. Special dictionary for storing URLs lets us keep scenario clean.
private static Dictionary<string, string> _Pages = new Dictionary<string, string>
{
{"Index", "http://localhost:64091/"},
{"Login", "http://localhost:64091/Account/Login"}
};
Implementation of navigation step is:
[Given(@"I am on the ""(.*)"" page")]
public void GivenIAmOnThePage(string page)
{
var url = _Pages[page];
Browser.GoTo(url);
}
To log in we need to fill fields for username and password and click button “Log in”:
[When(@"I have entered my credentials")]
public void WhenIHaveEnteredMyCredentials(Table table)
{
var user = table.Rows[0]["user"];
var password = table.Rows[0]["password"];
Browser.TextField(x => x.Id == "UserName").Value = user;
Browser.TextField(x => x.Id == "Password").Value = password;
}
As you’ve probably noticed, search is executed in DOM-tree by elements’ identifiers. After that, set up of fields’ values is done and the last step – looking for the button and calling Click:
[When(@"I have pressed ""(.*)"" button")]
public void WhenIHavePressedButton(string buttonLabel)
{
Browser.Button(x => x.Value == buttonLabel).Click();
}
Now we need to have some Asserts to check whether test succeeded. We’ll check what page are we currently on and what text-message we see on the screen. If authorization is executed correctly, user will see «Hello, <user_name>».
[Then(@"I should be on ""(.*)"" page")]
public void ThenIShouldBeOnPage(string page)
{
Assert.AreEqual(Browser.Url, _Pages[page]);
}
[Then(@"I should see the text ""(.*)""")]
public void ThenIShouldSeeTheText(string text)
{
var textOnPage = Browser.FindText(new Regex(text));
Assert.NotNull(textOnPage);
}
Now we can run our test.
During test execution the browser will be opened and user will be logged in. Test results will be shown on the tab Unit Test Session. Here are all steps and results of the test. Let’s add a few tests for data validation. For each recipe name is a mandatory field. Amount value for ingredients should be numeric. Let’s check this:
Scenario: Recipe name
Given I am logged as "user"
And I am on the "Recipe" page
When I put text "This is awesome recipe" to "Description" field
And I have pressed "Send" button
Then I should see the text "Please enter the recipe name"
Scenario: Ingredient amount
Given I am logged as "user"
And I am on the "Recipe" page
And I have selected "Squash" from ingredients
When I have pressed "Add" button
Then I should see the text "Please input valid numeric amount."
Some steps are already implemented.
[When(@"I put text ""(.*)"" to ""(.*)"" field")]
public void WhenIPutTextToField(string text, string field)
{
Browser.TextField(x => x.Name == field).Value = text;
}
[Given(@"I have selected ""(.*)"" from ingredients")]
public void GivenIHaveSelectedFromIngredients(string value)
{
Browser.SelectList(x => x.Id == "ingredient-list").SelectByValue(value);
}
After test-run we have all tests green. And one more scenario
Scenario: Recipe
Given I am logged as "user"
And I am on the "Recipe" page
When I put text "This is awesome recipe" to "Name" field
And I have selected "Egg" from ingredients
And I put text "100" to "Amount" field
And I have pressed "Add" button
And I have selected "Cucumber" from ingredients
And I put text "100" to "Amount" field
And I have pressed "Add" button
And I put text "This is awesome description" to "Description" field
And I have pressed "Send" button
Then I should see the text "This is awesome recipe"
And I should see the text "This is awesome description"
Its peculiarity is that for this scenario we don’t need to write implementations, everything was done before. Thus scenarios can be created from already existing “blocks”. BDD is evolutional phase of well-known TDD, that helps to minimize misunderstanding among Customers, business-analytics, developers and testers. Behavior-driven developers use their native language in combination with the ubiquitous language of domain-driven design to describe the purpose and benefit of their code. This allows developers to focus on why the code should be created, rather than the technical details, and minimizes translation between the technical language in which the code is written and the domain language spoken by the business, users, stakeholders, project management, etc. Watin + SpecFlow – powerful tools for Web application testing in BDD for C# language. Notice: I’ve also attached the link for the test project which I used in this article. Warning: if you are using the IE 11 you will probably need to turn off Protected Mode. 1. http://watin.org/documentation/sta-apartmentstate/ 2. http://watin.org/ 3. http://www.codeproject.com/Tips/658947/Watin-An-Automation-Testing-in-NET 4. http://msdn.microsoft.com/en-us/magazine/gg490346.aspx 5. https://github.com/confa/BDD-Project-Example