Hi,
I was playing a little bit with this idea. This is the code that I
finally created, maybe it gives you some other ideas for such tricks.
(Sorry for pasting longer code parts.)
Basically I have created a BeforeFeature event handler, that tries to
find the scenarios in the generated unit test class that are marked
with the "feature_setup" tag and executes that. It will also ignore
automatically the scenario if it is executed directly and not through
the feature setup. This all implemented in the following class, that
you can include to your project (please note, that this works
currently only with NUnit):
[Binding]
public class SpecialFeatureSetupTools
{
private const string FEATURE_SETUP_TAG = "feature_setup";
[BeforeScenario(FEATURE_SETUP_TAG)]
public static void IgnoreNormalExecution()
{
// ignore the scenario if it was executed through the
"normal" execution
bool value;
if
(FeatureContext.Current.TryGetValue("BeforeFeatureExecution", out
value) && value)
return;
Assert.Ignore("ignoring normal execution of the feature
setup");
}
[BeforeFeature]
public static void BeforeFeature()
{
var fixtureType = GetFixtureType();
if (fixtureType == null)
return;
object fixtureInstance = null;
var testRunner = TestRunnerManager.GetTestRunner();
FeatureContext.Current["BeforeFeatureExecution"] = true;
foreach (var featureSetupMethod in
fixtureType.GetMethods().Where(mi => IsTaggedWith(mi,
FEATURE_SETUP_TAG)))
{
if (fixtureInstance == null)
{
fixtureInstance =
Activator.CreateInstance(fixtureType);
}
featureSetupMethod.Invoke(fixtureInstance, null);
testRunner.OnScenarioEnd();
}
FeatureContext.Current["BeforeFeatureExecution"] = false;
}
private static Type GetFixtureType()
{
var stackTrace = new StackTrace(false).GetFrames();
if (stackTrace == null)
return null;
for (int frame = 0; frame < stackTrace.Length; frame++)
{
if (stackTrace[frame].GetMethod().Name ==
"OnFeatureStart")
{
return stackTrace[frame +
1].GetMethod().DeclaringType;
}
}
return null;
}
private static bool IsTaggedWith(MethodInfo mi, string
tagName)
{
var attributes = mi.GetCustomAttributes(typeof
(CategoryAttribute), false);
return attributes != null &&
attributes.Cast<CategoryAttribute>().Any(a => a.Name == tagName);
}
}
For testing, I have created a feature file like this:
Feature: Complex Feature Setup
In order to run a feature requiring a complex setup
As a stakeholder
I want to signal the required setup with a tag
@feature_setup
Scenario: Do some complicated setup
Given the complicated setup has executed 0 times
When I do some complicated setup
Scenario: A scenario requires complicated setup
Given the complicated setup has executed 1 times
Scenario: Another scenario requires complicated setup
Given the complicated setup has executed 1 times
and some steps for the test...
[Binding]
public class SpecialFeatureSetupSteps
{
[Given(@"the complicated setup has executed (\d+) times")]
public void GivenTheComplicatedSetupHasExecutedTimes(int
times)
{
int counter = GetCounter();
Assert.AreEqual(times, counter);
}
[When(@"I do some complicated setup")]
public void WhenIDoSomeComplicatedSetup()
{
int counter = GetCounter();
Console.WriteLine("doing some complex setup");
FeatureContext.Current["complex_setup_counter"] = +
+counter;
}
private int GetCounter()
{
int counter;
if (!
FeatureContext.Current.TryGetValue("complex_setup_counter", out
counter))
counter = 0;
return counter;