【问题标题】:SpecFlow/Cucumber/Gherkin - Using tables in a scenario outlineSpecFlow/Cucumber/Gherkin - 在场景大纲中使用表格
【发布时间】:2011-07-04 09:09:54
【问题描述】:

希望我能清楚地解释我的问题,让其他人理解,我们开始吧,假设我有以下两个假设场景:

Scenario: Filter sweets by king size and nut content
Given I am on the "Sweet/List" Page
When I filter sweets by 
    | Field               | Value  |
    | Filter.KingSize     | True   |
    | Filter.ContainsNuts | False  |
Then I should see :
    | Value            |
    | Yorkie King Size |
    | Mars King Size   |

Scenario: Filter sweets by make
Given I am on the "Sweet/List" Page
When I filter sweets by 
    | Field        | Value  |
    | Filter.Make  | Haribo |
Then I should see :
    | Value   |
    | Starmix |

这些场景很有用,因为我可以根据需要添加任意多的字段/值行和然后值条目,而无需更改相关的已编译测试步骤。然而,不同过滤器测试的复制/粘贴场景将变得重复并占用大量代码 - 我想避免这种情况。理想情况下,我想创建一个场景大纲并保持上面测试的动态特性,但是当我尝试这样做时,我遇到了定义示例表的问题,我无法添加我认为合适的新行,因为那将是一个新的测试实例,目前我有这个:

Scenario Outline: Filter Sweets 
Given I am on the <page> Page
When I filter chocolates by 
    | Field    | Value   |
    | <filter> | <value> |
Then I should see :
    | Output   |
    | <output> |
Examples:
    | page       | filter      | value  | output  |
    | Sweet/List | Filter.Make | Haribo | Starmix |

所以我遇到了在使用场景大纲时能够动态地将行添加到我的过滤器和预期数据的问题,有人知道解决这个问题的方法吗?我应该从不同的角度来解决这个问题吗?

解决方法可能类似于:

Then I should see :
    | Output |
    | <x>    |
    | <y>    |
    | <z>    |
    Examples:
    | x | y | z |

但这不是很动态....希望有更好的解决方案? :)

【问题讨论】:

    标签: cucumber automated-tests specflow gherkin


    【解决方案1】:

    我认为 SpecFlow、Gherkin 和开箱即用的 Cucumber 无法满足您的要求。我不能代表作者说话,但我敢打赌,它故意不打算以这种方式使用,因为它违背了编写和实施这些规范的整体“流程”。其中,规范旨在为非程序员阅读,为程序员提供实现与规范匹配的代码的指南,用于集成测试,并在重构时提供一定程度的灵活性。

    我认为这是您感到疼痛的一种情况,表明存在问题,但可能不是您想的那样。你说:

    “但是,不同过滤器测试的复制/粘贴场景将变得重复并占用大量代码 - 我想避免这种情况。”

    首先,我不同意以书面形式解释自己是“重复的”,至少与使用“the、apple、car 等”等特定词的重复性不同。一遍又一遍地。问题是:这些话是否正确地解释了你在做什么?如果是这样,并且解释您的情况需要您写出多个场景,那么这正是它所需要的。交流需要文字,有时甚至是相同的文字。

    实际上,您所说的“重复性”是使用 Gherkin 和 Cucumber 或 SpecFlow 之类的工具的好处之一。如果您能够一遍又一遍地使用该句子,这意味着您不必一遍又一遍地编写测试代码。

    第二,你确定你正在为正确的事情编写规范吗?我问只是因为如果场景的数量失控,以至于你有太多以至于人类无法理解你写的东西,那么你的规范可能没有针对正确的事情。

    这方面的一个可能示例可能是您在这种情况下如何测试过滤分页。是的,您希望您的规范涵盖全部功能,并且您的网站将在与您的过滤相同的页面上进行分页,但成本是多少?需要经验和实践才能知道什么时候放弃所谓的“理想”,即无模拟、完全集成测试会产生更好的结果。

    第三,不要认为规范是为了完美覆盖所有可能的情况。这些场景基本上是状态的快照,这意味着有些功能可以覆盖无限大的场景集,这是不可能的。所以你会怎么做?尽可能写出能够讲述故事的功能。甚至让故事驱动发展。但是,没有转化为您的规格或其他情况的细节最好留给直接 TDD,在规格之外完成。

    在您的示例中,您似乎基本上是在讲述一个关于一个网站的故事,该网站允许用户创建针对糖果和糖果的动态搜索。他们输入一大组可能的搜索条件中的一个,单击一个按钮,然后获得结果。坚持下去,只写足够的规格来完成这个故事。如果您对覆盖范围不满意,请使用更多规范或单元测试对其进行清理。


    这只是我的想法,希望对你有帮助。

    【讨论】:

    • Darren,非常感谢您的 cmets,我对 BDD 很陌生,他们非常有帮助,我同意您所写的内容,尤其是第三部分。我已经标记了您的答案,但将解决方案授予帕特里克,因为他为原始问题提供了技术解决方案。再次感谢。
    • SpecFlow(至少 v2)支持支持场景大纲示例的参数驱动表...此处示例:stackoverflow.com/a/37349163/307
    【解决方案2】:

    从技术上讲,我认为您可以尝试从步骤定义中调用步骤:

    Calling Steps from Step Definitions

    例如我认为你可以重写

    Then I should see :
    | Output   |
    | <output> |
    

    要像自定义步骤一样

    I should have output that contains <output>
    

    其中输出是一个逗号分隔的期望值列表。在自定义步骤中,您可以将逗号分隔的列表分解为一个数组并对其进行迭代调用

    Then "I should see #{iterated_value}"
    

    您可以使用类似的技术来传递过滤器列表和过滤器值。您的特大号测试示例行可能如下所示

    | page       | filter                               | value       | output                           |
    | Sweet/List | Filter.KingSize, Filter.ContainsNuts | True, False | Yorkie King Size, Mars King Size |
    

    或许

    | page       |                              filter-value-pairs | output                           |
    | Sweet/List | Filter.KingSize:True, Filter.ContainsNuts:False | Yorkie King Size, Mars King Size |
    

    话虽如此,你或许应该把达伦的话牢记在心。我不确定这种方法是否有助于实现非开发人员可读的场景的最终目标。

    【讨论】:

    • 嗨帕特里克,感谢您的 cmets。我已将此标记为正确答案,因为它为我最初的问题提供了一个解决方案,尽管我同意你和 Darren 的观点,但也许这会违背让非开发人员可以理解的场景的最终目标。
    猜你喜欢
    • 2021-04-29
    • 2021-04-10
    • 2014-10-12
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多