SpecFlow:ClassInitialize和TestContext

时间:2012-08-31 15:04:06

标签: c# mstest visual-studio-2012 specflow

首先,我是SpecFlow的新手。

我有一个功能文件,我已经/想要自动使用MSTest作为功能测试运行,涉及完全设置的服务器,数据访问...... 为此,我必须使用SpecFlow的'Given'块中的数据配置服务器,然后启动它。我还必须将一些文件复制到测试的输出目录。

在非SpecFlow功能测试中,我使用ClassInitialize属性从TestContext获取TestDeploymentDir;像这样的东西:

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

现在使用SpecFlow我不再使用此属性,因为SpecFlow本身使用它。 确实存在一些新属性,例如 BeforeFeature ,它的行为类似但是它不会将TestContext作为参数传递。

我只需要访问TestContext的TestDeploymentDir,以便在真正推出我的功能测试服务器之前复制一些文件 - 没有SpecFlow就可以轻松实现,但使用SpecFlow几乎不可能。

如何处理这个问题?

有可能吗?

非常感谢您的建议!

罗伯特


环境:

  • Visual Studio 2012
  • SpecFlow 1.9.0.77

4 个答案:

答案 0 :(得分:3)

为了能够访问TestContext中的值,您必须为添加的每个方案文件创建分部类。

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

然后,您可以使用

从步骤访问部署目录
var testContext = (TestContext)FeatureContext.Current["TestContext"];
var deploymentDir = testContext.TestDeploymentDir;

如果您有太多场景,那么您可能必须使用T4自动创建此类文件。

答案 1 :(得分:3)

您可以创建插件并自定义IUnitTestGeneratorProvider实现。以下内容应该将该行添加到MSTest的类初始化。

// 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)
        {
        }
    }

}

并在App.config文件中引用它:

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

下次重新保存.feature文件时,ClassInitialize中生成的代码应设置TargetDataDeploymentDirectory。

我必须做类似的事情。这是我的工作代码https://github.com/marksl/Specflow-MsTest和博文http://codealoc.wordpress.com/2013/09/30/bdding-with-specflow/

答案 2 :(得分:2)

从SpecFlow 2.2.1开始,TestContext可通过Context Injection获得。 (https://github.com/techtalk/SpecFlow/pull/882

您可以直接从容器中获取它:

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

或通过上下文注入:

forEach

答案 3 :(得分:-1)

  

有一个FeatureContext以及更常用的   ScenarioContext。当然,区别在于FeatureContext   在执行完整功能时存在   ScenarioContext仅在场景中存在。

例如:

添加到上下文中:

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

得到:

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

您可以详细了解here