SpecFlow:ClassInitialize 和 TestContext

Posted

技术标签:

【中文标题】SpecFlow:ClassInitialize 和 TestContext【英文标题】:SpecFlow: ClassInitialize and TestContext 【发布时间】:2012-08-31 15:04:06 【问题描述】:

首先我是 SpecFlow 的新手。

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

在非 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

【问题讨论】:

您可以使用 specflow 从您的功能文件生成 MSTest 测试:***.com/questions/2984318/… 感谢您的回复。我已经从我的功能文件生成 MSTest 测试,但如上所述,我无法访问 TestContext。 也许AssemblyInitialize 可以适用于您的场景,specflow 不要使用它。否则,使用当前MsTestGeneratorProvider 生成的功能文件,您无法获得提供的TestContext。但是,您可以从 MsTestGeneratorProvider 派生并生成将 TestContext 存储在 specflow 内某处的测试。 感谢您的建议。听起来肯定不错 - 我很快就会试一试。 在哪里可以找到这个 MsTestGeneratorProvider?可以举个例子吗? 【参考方案1】:

自 SpecFlow 2.2.1 起,TestContext 可通过上下文注入获得。 (https://github.com/techtalk/SpecFlow/pull/882)

可以直接从容器中获取:

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

或通过上下文注入:

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
     

【讨论】:

【参考方案2】:

为了能够访问 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 自动创建此类文件。

【讨论】:

如果您使用这种技术,当您升级到 SpecFlow 2.2.1 时,您需要稍微修改一下。看看这里:github.com/techtalk/SpecFlow/issues/936【参考方案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/

【讨论】:

【参考方案4】:

还有一个FeatureContext以及比较常用的 场景上下文。不同之处当然在于 FeatureContext 在完整功能的执行过程中存在,而 ScenarioContext 只存在于一个场景中。

例如:

添加到上下文:

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

获取:

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

您可以阅读更多关于它的信息here。

【讨论】:

早上好,我已经看到了,如果我能把我的 TestContext 的属性放在那里就好了。这怎么可能?这对我来说是一个阻塞问题!非常感谢您的建议,罗伯特

以上是关于SpecFlow:ClassInitialize 和 TestContext的主要内容,如果未能解决你的问题,请参考以下文章

在 TFS 构建中运行 Specflow 测试

SpecFlow:场景大纲示例

SpecFlow测试平台是否支持异步任务?

Specflow - 场景大纲测试被忽略

Specflow 与 .feature 文件的关联

SpecFlow - 是不是可以在功能文件中重用测试数据?