SpecFlow: ClassInitialize and TestContext

独自空忆成欢 提交于 2019-12-05 03:32:59

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.

Marksl

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/

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
    } 
}

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!