是否可以以编程方式向场景添加行?

Chr*_*yne 5 specflow

我想在每个SpecFlow测试的开头添加相同的行.

此行指定了一些随时间变化的场景列表,因此不可能为每个测试维护此列表.

例如:

Given I have set my site theme to <MyTheme>
    |Theme Names|
    |Theme 1    |
    |Theme 2    |
    |Theme 3    |
    |Theme 4    |
    |Theme 5    |
Run Code Online (Sandbox Code Playgroud)

我想对每个主题重复这个测试.主题列表不是一成不变的,应该保存在一个地方.

到目前为止,我已成功设法创建了一个Generator Plugin,我计划在生成测试类之前立即使用此插件来更改SpecFlow功能.但是,我无法在此上下文中看到编辑方案的方法.

是否可以从实现中获取和设置场景文本IUnitTestGeneratorProvider

我没有开始使用这种方法,所以如果有人能提出更好的方法来做到这一点,那么我也会接受.

如果我得到一些错误的术语,我会道歉 - 我刚刚开始使用SpecFlow.

编辑:

我正在添加这一部分,以澄清我实际上在追求什么.

假设我有一个包含800个测试的测试套件.我们有业务要求在每个可用主题上运行800个测试中的每一个.可用主题列表可以随时更改,并且将此列表保留在多个位置是不可行的.

所以,例如,如果我有以下两个测试:

例A:

    Given I set context to < site >
    Given I go to base url
    When I type <username> in username field
    When I type <password> in password field
    When I click login button
    Examples:
        | site         | username  | password   |
        | MySuperSite  | chris     | mypassword |
        | MySuperSite2 | chris2    | mypassword |



    Given I am logged in
    Given I go to base url
    When I click logout button
    Then I am logged out
Run Code Online (Sandbox Code Playgroud)

我可以简单地手动将这些测试更改为以下内容:

例B:

    Given I am using the < theme > theme
    Given I set context to < site >
    Given I go to base url
    When I type <username> in username field
    When I type <password> in password field
    When I click login button
    Examples:
        | site         | username  | password   | theme  |
        | MySuperSite  | chris     | mypassword | theme1 |
        | MySuperSite2 | chris2    | mypassword | theme1 |
        | MySuperSite  | chris     | mypassword | theme2 |
        | MySuperSite2 | chris2    | mypassword | theme2 |
        | MySuperSite  | chris     | mypassword | theme3 |
        | MySuperSite2 | chris2    | mypassword | theme3 |



    Given I am using the < theme > theme
    Given I am logged in
    Given I go to base url
    When I click logout button
    Then I am logged out
    Examples:
        | theme  |
        | theme1 |
        | theme2 |
        | theme3 |
Run Code Online (Sandbox Code Playgroud)

这有一些问题:

  • 测试变得臃肿,重复的数据
  • 如果我们不再选择支持,theme2那么有人将不得不通过每个测试并将其从示例表中删除(在上面的示例中不是太糟糕,但是成像我们有> 800个测试)
  • 已有示例表的测试将其表大小乘以我们支持的主题数(> 40)
  • 由于某人无意中忘记在测试中添加特定主题而导致手动错误的风险很大

目标: 我希望能够让我们的测试人员以他们的风格编写测试Example A,但是测试本身会编译成他们如何按照风格编写Example B.

我已经为specflow创建了一个生成器插件,其中包含拦截测试创建然后以编程方式添加行的视图Given I am using the < theme > theme,然后根据需要更新或添加任何示例数据.但是,我似乎无法从这里做到这一点.

任何人都可以告诉我这是否可能,如果可以的话,我应该怎么做呢?

Chr*_*yne 5

好的,我想出来了.它花了几个步骤:

在浏览了GitHub上的源代码之后,我发现UnitTestFeatureGenerator哪个似乎是负责将specflow文件转换为单元测试的类.

然后我创建了一个从基类继承UnitTestFeatureGenerator并隐藏GenerateUnitTestFixture方法的新类.

在我的GenerateUnitTestFixture课程正文中,然后在交付base.GenerateUnitTestFixture生成单元测试之前,在场景中添加所需的额外步骤.这是它的要点:

public class MultiThemeUnitTestFeatureGenerator : UnitTestFeatureGenerator, IFeatureGenerator
{
    public MultiThemeUnitTestFeatureGenerator(IUnitTestGeneratorProvider testGeneratorProvider, CodeDomHelper codeDomHelper, GeneratorConfiguration generatorConfiguration, IDecoratorRegistry decoratorRegistry)
        : base(testGeneratorProvider, codeDomHelper, generatorConfiguration, decoratorRegistry)
    {}

    public new CodeNamespace GenerateUnitTestFixture(Feature feature, string testClassName, string targetNamespace)
    {
        foreach (var scenario in feature.Scenarios)
        {
            scenario.Steps.Insert(0, new Given {Text = "Given I have <Theme> set as my current theme"});

            //add any other steps you need....
        }

        return base.GenerateUnitTestFixture(feature, testClassName, targetNamespace);
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦我完成了所有这些设置,我需要一种方法来告诉specflow使用我的新类而不是当前注册的UnitTestFeatureGenerator.这是一个复杂的工作,因为文档几乎只是说"即将推出".值得庆幸的是,我发现了一篇精彩的博文,其中概述了所有陷阱.

我的IGeneratorPlugin实现看起来像这样:

public class MultiThemeGeneratorPlugin : IGeneratorPlugin
{
    public void RegisterDependencies(ObjectContainer container)
    {}

    public void RegisterCustomizations(ObjectContainer container, SpecFlowProjectConfiguration generatorConfiguration)
    {
        container.RegisterTypeAs<MultiThemeFeatureGeneratorProvider, IFeatureGeneratorProvider>("default");
    }

    public void RegisterConfigurationDefaults(SpecFlowProjectConfiguration specFlowConfiguration)
    {}
}
Run Code Online (Sandbox Code Playgroud)

注意我注册IFeatureGeneratorProvider而不是IFeatureGenerator.我必须创建一个实现IFeatureGeneratorProvider,返回IFeatureGenerator我感兴趣的实现的实例:

public class MultiThemeFeatureGeneratorProvider : IFeatureGeneratorProvider
{
    private readonly ObjectContainer _container;

    public MultiThemeFeatureGeneratorProvider(ObjectContainer container)
    {
        _container = container;
    }

    public int Priority
    {
        get { return int.MaxValue; }
    }

    public bool CanGenerate(Feature feature)
    {
        return true;
    }

    public IFeatureGenerator CreateGenerator(Feature feature)
    {
        return _container.Resolve<MultiThemeUnitTestFeatureGenerator>();
    }
}
Run Code Online (Sandbox Code Playgroud)