9
votes

first of all I'm new to SpecFlow.

I have a feature file which I have / want to automate using MSTest to run as a functional test involving a fully set up server, data access ... For this purpose I have to configure the server with the data in the SpecFlow's 'Given' blocks and start it afterwards. I also have to copy some files to the test's output directory.

In the non-SpecFlow functional tests I was using the ClassInitialize attribute to get the TestDeploymentDir from the TestContext; something like this:

[ClassInitialize]
public static void ClassSetup(TestContext context)
{
  TargetDataDeploymentRoot = context.TestDeploymentDir;
}

Now with SpecFlow I can't use this attribute anymore as it is used by SpecFlow itself. Some new attributes do exist, like BeforeFeature which acts similarly BUT it doesn't pass on the TestContext as a parameter.

I just need to get access to the TestContext's TestDeploymentDir in order to copy some files there before really lauching my functional test server - easily doable without SpecFlow but almost impossible with SpecFlow.

How to deal with this issue?

Is it possible at all?

Thanks a lot for advice!

robert


Environment:

  • Visual Studio 2012
  • SpecFlow 1.9.0.77
4
You can generate MSTest tests from your feature fiels with specflow: stackoverflow.com/questions/2984318/…nemesv
Thanks for the response. I'm already generating MSTest tests from my feature files, but as mentioned above, the I have no access to the TestContext.robert.oh.
Maybe the AssemblyInitialize can work for your scenario, specflow don't use it. Otherwise with the current MsTestGeneratorProvider generated feature files you cannot get the provied TestContext. However you can derive from MsTestGeneratorProvider and generate tests which stores the TestContext somewhere inside specflow.nemesv
Thanks for advice. It definitely sounds good - I'll give it a try soon.robert.oh.
Where do I find this MsTestGeneratorProvider? Can you maybe provide an example?robert.oh.

4 Answers

5
votes

Since SpecFlow 2.2.1 the TestContext is available via Context Injection. (https://github.com/techtalk/SpecFlow/pull/882)

You can get it from the container directly:

ScenarioContext.Current.ScenarioContainer.Resolve<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>()

or via context injection:

public class MyStepDefs
{
    private readonly TestContext _testContext;
    public MyStepDefs(TestContext testContext) // use it as ctor parameter
    { 
        _testContext = testContext;
    }

    [BeforeScenario()]
    public void BeforeScenario()
    {
        //now you can access the TestContext
    } 
}
3
votes

In order to have access to values in the TestContext you have to create partial class for each scenario file you have in which you add the .

using Microsoft.VisualStudio.TestTools.UnitTesting;
using TechTalk.SpecFlow;

/// <summary>
/// Partial class for TestContext support.
/// </summary>
public partial class DistributionFeature
{
    /// <summary>
    /// Test execution context.
    /// </summary>
    private TestContext testContext;

    /// <summary>
    /// Gets or sets test execution context.
    /// </summary>
    public TestContext TestContext
    {
        get
        {
            return this.testContext;
        }

        set
        {
            this.testContext = value;

            //see https://github.com/techtalk/SpecFlow/issues/96
            this.TestInitialize();
            FeatureContext.Current["TestContext"] = value;
        }
    }
}

Then you could access the deployment directory from your steps using

var testContext = (TestContext)FeatureContext.Current["TestContext"];
var deploymentDir = testContext.TestDeploymentDir;

If you have too many scenarios, then you probably has to automate creation of such files with T4.

3
votes

You can create a Plugin and customize the IUnitTestGeneratorProvider implementation. The following should add the line to MSTest's class initialize.

// It's very important this is named Generator.SpecflowPlugin.
namespace MyGenerator.Generator.SpecflowPlugin
{
    public class MyGeneratorProvider : MsTest2010GeneratorProvider
    {
        public MyGeneratorProvider(CodeDomHelper codeDomHelper)
            : base(codeDomHelper)
        {
        }

         public override void SetTestClassInitializeMethod(TestClassGenerationContext generationContext)
        {

            base.SetTestClassInitializeMethod(generationContext);

generationContext.TestClassInitializeMethod.Statements.Add(new CodeSnippetStatement(
                                                                      @"TargetDataDeploymentRoot = context.TestDeploymentDir;"));

        }

     }


[assembly: GeneratorPlugin(typeof(MyGeneratorPlugin))]

    public class MyGeneratorPlugin : IGeneratorPlugin
    {
        public void RegisterDependencies(ObjectContainer container)
        {
        }

        public void RegisterCustomizations(ObjectContainer container, SpecFlowProjectConfiguration generatorConfiguration)
        {
            container.RegisterTypeAs<MyGeneratorProvider, IUnitTestGeneratorProvider>();
        }

        public void RegisterConfigurationDefaults(SpecFlowProjectConfiguration specFlowConfiguration)
        {
        }
    }

}

And reference it in the App.config file:

<specFlow>
    <plugins>
      <add name="MyGenerator" type="Generator"/>
    </plugins>
 </specFlow>

Next time you re-save the .feature files the generated code in ClassInitialize should set the TargetDataDeploymentDirectory.

I had to do something similar. Here's my working code https://github.com/marksl/Specflow-MsTest and blog post http://codealoc.wordpress.com/2013/09/30/bdding-with-specflow/

-1
votes

There is a FeatureContext as well as the more commonly used ScenarioContext. The difference of course is that the FeatureContext exists during the execution of the complete feature while the ScenarioContext only exists during a scenario.

For example:

Add to context:

ScenarioContext.Current.Add("ObjectName", myObject);

Get:

var myObject = ScenarioContext.Current.Get<object>("ObjectName");

You can read more about it here.