In this post I show how to use SpecFlow and Xamarin UITest to run automated tests written in Gherkin. The source of my demo solution is available here.
Why should you care?
The big benefit of this is that you can take a specification written by non technical team members and turn it into tests that prove that the app behaves corectly.

BDD, Gherkin, and SpecFlow
Behaviour Driven Development (BDD) is an approach to software development that uses specifications written in natural language to verify that the product is behaving correctly. This enhances communication between more and less technical team members and ensures that the correct product gets built.
Gherkin is a language for describing softwares behaviour, without specifying how the behaviour is implemented. This means it can be written by non technical team members. A Gherkin file is made up of features, scenarios, and steps. Here’s the feature that will be tested in the demo app…
Feature: Log in to app Scenario: Olivia logs in to app Given the login page is displayed When Olivia enters the username Olivia And she enters the password IHeartOwls And she presses the Logon button Then the home screen is displayed Scenario: Olivia uses the wrong password Given the login page is displayed When Olivia enters the username Olivia And she enters the password IHateTrees And she presses the Logon button Then an invalid username or password message is displayed
They key thing here is anyone could have written it and it describes how the app behaves, not how it is implemented. Obviously in the real world there would be more scenarios!
SpecFlow is a .net tool to run the tests based on the features that are written in Gherkin.
Prerequisites
For Mac development in Visual Studio
– Straight8’s SpecFlow Integration
For Windows development in Visual Studio
– SpecFlow for Visual Studio 2017
Solution Setup
These instructions assume that you have a working app which isn’t set up for UITest. The first thing to do is add a UITest project to the solution.
The new UITest project has a Tests.cs file which should be deleted.
Next you need to make sure the appropriate automation ids are present in the apps interface. For example here’s the login page from the demo app. You can see that Automation Ids are present for the page, both entries and the login button.
Finally you need to add a reference to SpecFlow via NuGet. You need to be careful here because some of the SpecFlow packages use versions of Nunit which aren’t compatible with UITest or Test Cloud. The packages in the demo are…
Writing the Tests
Now we are ready to start writing the tests. Add a new SpecFlow Feature file to the test solution and add the appropriate Gherkin scenarios.
Now you can try to run the tests, but you’ll get a bunch of inconclusive results with the message ‘No matching step definition found for…’. You need to write the step definitions which are control the actions that occur for each step.
Add a SpecFlow Step Definition file called Steps.cs to the project. The example methods show how to bind a method to a step but they can all be replaced with steps based on the feature file. You can generate the code for the steps via a right click in the feature file.
Now you can define the steps. Here’s the file for the demo app…
using Xamarin.UITest; using TechTalk.SpecFlow; namespace SpecFlowDemo.UITests { [Binding] public class Steps { private IApp app; [Given("the login page is displayed")] public void TheLoginPageIsDisplayed() { app = ConfigureApp.Android.StartApp(); app.WaitForElement("LoginPage"); } [When("Olivia enters the username Olivia")] public void OliviaEntersTheUsernameOlivia() { app.EnterText("UsernameEntry", "Olivia"); } [When("she enters the password IHeartOwls")] public void WhenSheEntersThePasswordIHeartOwls() { app.EnterText("PasswordEntry", "IHeartOwls"); app.DismissKeyboard(); } [When("she enters the password IHateTrees")] public void WhenSheEntersThePasswordIHateTrees() { app.EnterText("PasswordEntry", "IHateTrees"); app.DismissKeyboard(); } [When("she presses the Logon button")] public void ShePressesTheLogonButton() { app.Tap("LoginButton"); } [Then("the home screen is displayed")] public void TheHomeScreenIsDisplayed() { app.WaitForElement("MainPage"); } [Then("an invalid username or password message is displayed")] public void AnInvalidUsernameOrPasswordMessageIsDisplayed() { app.WaitForElement("Logon Failed"); app.WaitForElement("Invalid username or password"); } } }
Note that in the first step we set up the UITest application object. This works but it means that tests can only run on either iOS or Android. Fortunately it’s easy to get it running on both…
Support for iOS and Android
To support both platforms we need to take advantage of the fact that SpecFlow is based around nunit, and that it creates partial classes for it’s test definitions. Add a new file called TestPartials.cs to the solution.
using System; using NUnit.Framework; using Xamarin.UITest; namespace SpecFlowDemo.UITests { public static class Global { public static Platform Platform { get; set; } public static IApp App { get; set; } } [TestFixture(Platform.iOS)] [TestFixture(Platform.Android)] public partial class LogInToAppFeature { public LogInToAppFeature(Platform platform) { Global.Platform = platform; } } }
By adding a partial class for each feature like this you ensure they will run for both platforms. The Globals.Platform flag is set so that the app can be configured. The first step needs to be changed to pick this up…
[Given("the login page is displayed")] public void TheLoginPageIsDisplayed() { if (Global.Platform == Platform.iOS) { Global.App = ConfigureApp.iOS.StartApp(); } else { Global.App = ConfigureApp.Android.StartApp(); } Global.App.WaitForElement("LoginPage"); }
Code Improvements
So it’s all working nicely but there are a few things that can be improved. SpecFlow supports passing parameters to step definitions so we only need one definition to set the password. This is done by added a regular expression to capture the parameter to the definition’s attribute, and adding the parameter to the method’s signature. Here’s how it works for the password…
[When("she enters the password (.*)")] public void WhenSheEntersThePassword(string password) { Global.App.EnterText("PasswordEntry", password); Global.App.DismissKeyboard(); }
Another thing that’s worth considering is splitting the step definitions into separate files instead of big one. I have found that one file per screen is a good starting point. As long as the [Binding] attribute is present you can put the definitions wherever you want…
using Xamarin.UITest; using TechTalk.SpecFlow; namespace SpecFlowDemo.UITests { [Binding] public class MainPageSteps { [Then("the main page is displayed")] public void TheMainPageIsDisplayed() { Global.App.WaitForElement("MainPage"); } } }
Typically you’ll want to run some steps at the start of each test to set up a clean environment, and start the app. Cucumber uses the Background keyword for this…
Feature: Log in to app Background: Given a started app Scenario: Olivia logs in to app Given the login page is displayed When Olivia enters the username Olivia ...
using Xamarin.UITest; using TechTalk.SpecFlow; namespace SpecFlowDemo.UITests { [Binding] public class SetupSteps { [Given("a started app")] public void TheMainPageIsDisplayed() { if (Global.Platform == Platform.iOS) { Global.App = ConfigureApp.iOS.StartApp(); } else { Global.App = ConfigureApp.Android.StartApp(); } } } }
So that’s it! BDD for mobile apps via Xamarin UITest and SpecFlow. Give it a go and let me know how you get on 🙂