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的主要内容,如果未能解决你的问题,请参考以下文章