如何将 Specflow 步骤标记为 'Obsolete' 以支持渐进式、向后兼容的重构

How to mark Specflow steps as 'Obsolete' to support progressive, backwards compatible refactoring

由于业务术语中的一些术语更改,我目前正在重构一个中型应用程序。我们有大约 121 个 SpecFlow 功能文件需要更改。

我喜欢你如何在 C# 中 "deprecate" 一个 API,首先作为警告:

[Obsolete("Use MyClass.NewMethod instead")]
public void OldMethod() { }

然后编译错误:

[Obsolete("Use MyClass.NewMethod instead", true)]
public void OldMethod() { }

如果 SpecFlow 步骤有这种功能就好了:

[When("I old foo", Obsolete = true)]
[When("I new foo")]
public void WhenIFoo() { }

是否有任何方法可以将 SpecFlow 中的步骤标记为过时,以便其他开发人员知道需要在他们的功能文件中更改这些步骤,但不会阻止他们创作和 运行ning 测试? 作为额外的奖励,有没有办法选择性地导致编译器或测试 运行 失败?

我仍然没有直接在 SpecFlow 中找到解决方案,但我使用 ScenarioContext 的扩展方法找到了 Get It To Work™:

注意:这使用了 MsTest,但我确信其他单元测试框架有办法将测试标记为 "pending" 或带有消息的不确定性。

using TechTalk.SpecFlow;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MyTestProject
{
    public static class ScenarioContextExtensions
    {
        public static void MarkStepObsolete(this ScenarioContext scenario, string newStep, params object[] newStepFormatArgs)
        {
            var message = string.Format(@"This step is obsolete. Use '" + scenario.CurrentScenarioBlock + " " + newStep + "' instead.", newStepFormatArgs);

            Assert.Inconclusive(message);
        }
    }
}

现在,在您的步骤定义中,您创建了旧步骤 "obsolete",它们显示为不确定的测试,提示您更换步骤:

[When(@"I click the ""(.*)"" anchor")]
public void WhenIClickTheAnchor(string anchorText)
{
    ScenarioContext.Current.MarkStepObsolete(@"I click the ""{0}"" link", anchorText);
}

[When(@"I click the ""(.*)"" link")]
public void WhenIClickTheLink(string linkText)
{
    // ...
}

它显示在测试资源管理器面板中:

Assert.Inconclusive Failed - This step is obsolete. Use 'When I click the "Home" link' instead.

这至少告诉其他开发人员如何在我更改现有场景中的术语时修复他们正在编写的新测试。

有一种方法可以完成 Scopes:

[When("I old foo", Scope(Tag = "Obsolete"))]
[When("I new foo")]
public void WhenIFoo() { }

确保标签(它是一个正则表达式)是唯一的,因为这个想法是不匹配任何标记的场景。

您的测试将被标记为 Not Run,更重要的是,使用此步骤的场景将获得粉红色步骤 ,因此编译时间可见。

如果要将整个 class 标记为过时,只需按如下方式标记 class:

[Binding, Scope(Tag = "Obsolete")]
public class Steps

参考: https://github.com/techtalk/SpecFlow/wiki/Scoped-bindings#scoping-tips--tricks

version v2.4 开始,SpecFlow 遵循步骤绑定上的 [Obsolete] 属性。

对于您的示例,您可能会这样使用它:

[When("I old foo")]
[Obsolete("you should use WhenIFoo instead")]
public void WhenIOldFoo() { }

[When("I new foo")]
public void WhenIFoo() { }

作为使用此类步骤的默认行为,会发出警告。利用 SpecFlow 的 <runtime> 配置上的 obsoleteBehavior 属性,您可以更改它,尤其是。测试执行失败:

<specFlow>
    ...
    <runtime obsoleteBehavior="Error" />
</specFlow>

同时 Wiki-page for the Configuration 已更新以记录该功能。