I'm using specflow with the NUnit test runner. When I write my feature file and ask specflow to generate the steps, it outputs the following code:
using System;
using TechTalk.SpecFlow;
using Xamarin.UITest.Android;
namespace UITest1
{
[Binding]
public class CategoryPagerSteps
{
[Given(@"The (.*)st category is selected")]
public void GivenTheStCategoryIsSelected(int p0)
{
ScenarioContext.Current.Pending();
}
[When(@"I swipe left")]
public void WhenISwipeLeft()
{
ScenarioContext.Current.Pending();
}
[Then(@"The (.*)nd category is selected")]
public void ThenTheNdCategoryIsSelected(int p0)
{
ScenarioContext.Current.Pending();
}
}
}
This is fine, and I understand that these are "Steps" which will be called when my cucumber file with scenarios written in Gherkin calls for them.
However, being that this is a fully-integrated UI test, I need to be able to use Xamarin.UITest.Android to click on views and such.
So I need to somehow grab the object that represents the application that is under test so I can perform UI operations on it.
Now, I can see that this object is being initialized in another auto-generated test fixture file called "Tests.cs":
using NUnit.Framework;
using Xamarin.UITest;
using Xamarin.UITest.Android;
namespace UITest1
{
[TestFixture]
public class Tests
{
AndroidApp app;
[SetUp]
public void BeforeEachTest()
{
// TODO: If the Android app being tested is included in the solution then open
// the Unit Tests window, right click Test Apps, select Add App Project
// and select the app projects that should be tested.
app = ConfigureApp
.Android
// TODO: Update this path to point to your Android app and uncomment the
// code if the app is not included in the solution.
//.ApkFile ("../../../Android/bin/Debug/UITestsAndroid.apk")
.StartApp();
}
[Test]
public void AppLaunches()
{
app.Screenshot("First screen.");
}
}
}
I can see that the property AndroidApp app
is the object that I need access to, but how do I access that property from the CategoryPagerSteps
code above? Tests
is not static nor are any of the methods or properties. I'm nervous to simply instantiate it myself because that should probably be done by the test runner, right? One of the other auto-generated files contains a testRunner property, but it is marked private.
So every avenue I've gone down appears blocked and I feel that I'm missing something obvious.
Here's how I solved it, in case anyone else might find it useful:
Following up on the link provided by @CheeseBaron from arteksoftware, the trick is to use SpecFlow's FeatureContext.Current
to hold the value. This is one of the intended uses of FeatureContext
.
The reference from arteksoftware used this method, as shown in this code:
[SetUp]
public void BeforeEachTest ()
{
app = AppInitializer.StartApp (platform, iOSSimulator);
FeatureContext.Current.Add ("App", app);
//This next line is not relevant to this post.
AppInitializer.InitializeScreens (platform);
}
However, it didn't work immediately for me because the [Setup]
binding would not be called as part of a specflow test. Changing the binding to the SpecFlow [BeforeFeature]
binding and making the method static solved the problem.
[BeforeFeature]
public static void Before()
{
AndroidApp app;
Console.WriteLine("** [BeforeFeature]");
app = ConfigureApp
.Android
// TODO: Update this path to point to your Android app and uncomment the
// code if the app is not included in the solution.
.ApkFile(<Path to APK>)
.StartApp();
FeatureContext.Current.Add("App", app);
}
Then, in the feature code itself, the app could be extracted from the FeatureContext
dictionary like so:
[Binding]
public class FeatureSteps
{
AndroidApp app;
public FeatureSteps()
{
app = FeatureContext.Current.Get<AndroidApp>("App");
}
//Code for the rest of your feature steps.
}
I imagine that the selection of one's test runner is relevant to the bindings that are used, so here's my "App.config". I'm using NUnit with a SpecFlow plugin. I didn't try it with other test runner configurations.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
</configSections>
<specFlow>
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
<!-- use unit test provider SpecRun+NUnit or SpecRun+MsTest for being able to execute the tests with SpecRun and another provider -->
<unitTestProvider name="NUnit" />
<plugins>
<add name="SpecRun" />
</plugins>
</specFlow>
</configuration>