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

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


【解决方案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 自动创建此类文件。

    【讨论】:

    【解决方案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 的属性放在那里就好了。这怎么可能?这对我来说是一个阻塞问题!非常感谢您的建议,罗伯特
      猜你喜欢
      • 2014-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      相关资源
      最近更新 更多