使用Specflow的外部BDD开发方法

43

我对BDD还很陌生,但是我发现它非常有趣并希望使用BDD开发我的下一个项目。在搜索和观看屏幕录制后,我仍然有很多关于BDD在实际中的问题。

1. 声明式或命令式的场景?

我看到的大多数given-when-then场景都是以UI(命令式)为基础编写的。

Scenario: Login
     Given I am on the Login-page
     When I enter 'AUser' in the textbox 'UserName'
       And I enter 'APassword' in the textbox 'Password'
       And I click the 'Login' button
     Then I should see the following text 'You are logged in'

我发现这些测试非常脆弱,并且对于点击按钮的业务价值没有什么帮助。我认为它们很难维护。为什么大多数示例都使用命令式场景?

Scenario: Login (declarative)
     Given I am not logged in
     When I log in using valid credentials
     Then I should be logged in

如果你更喜欢声明式的风格,那么如何描述像“主页”或“产品页面”这样的内容呢?

2. 是否运用UI进行练习?

大多数步骤实现都使用 WatiN、White 或其他类似工具来从用户角度实现场景。启动浏览器,点击按钮。我认为这些方法极其缓慢且易于破裂。好吧,我可以使用 Page 对象使测试不那么脆弱。但那又是一项额外的工作,特别是对于具有复杂 UI 的桌面应用程序。

在现实项目中如何实现场景 - 运用 UI 还是通过测试控制器/Presenter?

3. 使用真实数据库还是虚拟库?

当场景的 Given 部分被实现时,往往需要系统中有一些数据(例如,购物应用程序的某些商品)。那么你如何实现这个部分 - 将数据添加到真实数据库(完全端到端测试),还是向控制器提供存储库存根?

期待经验丰富的答案!

更新:问题上添加了有用的链接。


我喜欢这个问题,所以我点了赞,但是最后变得太宽泛了。你能把它分成多个SO问题吗,这样人们就可以单独回答并给出“正确”的答案了吗? - Merlyn Morgan-Graham
我考虑过这个问题。但我认为答案可能会很简洁,因为这不是关于BDD理论、每种方法的利弊。这是关于如何将BDD应用于实际项目中的问题。例如,我们试图从控制器开始,但在UI方面出现了很多错误,所以现在我们使用Watin进行测试。规格说明是声明性的,因为脚本很难维护并与客户讨论。 :) 也许还需要几行。 - Sergey Berezovskiy
3个回答

13
  1. 在我看来,声明式是正确的方式。如果你正在谈论页面.aspx文件名,那么你正在做错事。故事的目的是促进开发人员和非开发人员之间的沟通。非开发人员不关心products.aspx,他们关心的是产品列表。你的系统能够为非开发人员提供价值。这就是你想要捕捉的内容。

  2. 故事讲述了你需要实现的高级功能。这是你的系统必须完成的任务。真正判断你是否已经完成此任务的唯一方法是测试用户界面。对我而言,BDD SpecFlow故事并不能替代单元测试,它们更像是集成测试。如果你打破了这个,你就破坏了业务从你的软件中获取的价值。单元测试是用户不关心的实现细节,并且它们只测试每个部分的隔离性。这无法告诉你A和B是否始终一起工作(理论上应该可以,在实践中,当两个部分相互配合时,会发生有趣的[读:意外的]事情)。自动化端到端测试也可以帮助你的QA。如果一个功能区域出现问题,你就会知道,他们可以在应用程序的其他区域花费时间,而你可以确定是什么破坏了集成测试。

  3. 这是一个棘手的问题。我们采用了混合方法。我们确实使用数据库(毕竟集成测试是测试系统作为一个整体运行,而不是测试各个组件),但我们不会一直重置配置,而是在需要时使用Deleporter将我们的存储库替换为Moqs。看起来还不错,但肯定有优缺点。我认为我们仍然在自己摸索中。


7
编辑:我刚刚找到了这篇文章,介绍了仅谈论特定领域以避免脆弱情况的概念

他的主要观点是,你可以谈论的最少领域是问题领域和解决方案领域。如果你谈论的是这两个领域之外的任何事情,那么你就会涉及太多的利益相关者,引入太多的噪音,并使你的场景变得脆弱。

他还提到了一种称为“分块”的认知模型,称绝对的“声明式”或“命令式”模型是一种神话。他说,在你的抽象层次的任何水平上,你都可以“向上分块”或“向下分块”。这意味着你可以更明确(如何?)或更元(什么或为什么?)。通过问“我们在做什么?”来从命令式模型中向上分块,通过说“我们将如何做到这一点?”来向下分块。所以我想我不会过于拘泥于声明式与命令式——对于这个问题而言,这并没有帮助。

找出每个术语所属的领域,可能需要通过确定该术语所属的领域专家来实现。一旦确定了所有领域,就可以选择相关术语,这些术语位于某个场景中最突出的领域之一,或者完全删除不相符的语句。如果这还不够,您可以分割、进一步说明或移动场景,以满足这些要求。
顺便说一句,他还在 UI 登录场景中使用了具体指导 :)
编辑前:(仍然适用部分。“数据库与否”和“UI 与否”问题无关)
1 - 声明式或命令式场景?
尽可能使用声明式,虽然在项目生命周期的某些时候,命令式有一定价值。
对于测试人员和业务分析师不太熟悉信息理论和设计的人来说,命令式是一种更容易思考的方式。在项目早期,在您确定问题域和工作流程之前,命令式场景也更容易思考。它对于探索性思考非常有用。

声明式编程相对于命令式编程更加稳定。由于GUI是应用程序中最容易随意更改的部分,因此这非常有价值。一旦确定了问题域和工作流程,并且更加关注关系概念,就更容易思考。它是一个更稳定和更普遍适用的模型。

如果您使用通用和声明性模型编写测试用例,则可以使用任何组合的完整应用程序GUI自动化、集成测试或单元测试来实现它们。

如何描述“主页”或“产品页面”之类的东西?

我不确定在特征和需求的基本级别上是否需要。您可能会创建描述实现细节(如特定UI工作流程)的子特征和子需求。如果您正在描述UI的一部分,则应定义UI特征/需求。

2- 是否要练习UI?

两者都可以。

我认为它非常缓慢和脆弱

是的,它是。使用UI和完整的DB集成执行每个高级场景/要求,但不要使用端到端UI自动化来执行每个单独的代码路径,当然也不包括边缘情况。如果这样做,你将花费更多时间让它们正常工作,而实际上测试应用程序的时间会少得多。
你可以设计你的应用程序,以便进行低成本的集成测试,包括基于单个UI的测试。单元测试也很有价值。
但是你做的集成测试越少,就会错过更多让人想拍自己额头的错误。编写单元测试可能更容易,并且它们肯定会更加稳定,但是根据定义,你将测试更少的应用程序部分。
3 - 真实数据库还是虚拟数据库?
两者都有。
必须使用完整系统进行高级端到端集成测试。这包括真实的数据库,在每个系统上运行测试并在不同的服务器上运行等。
你越深入细节,我就越支持模拟对象。
  • 单元测试应该只测试单个类
  • 中级集成测试应该避免使用昂贵、脆弱和有影响力的依赖项,比如文件系统、数据库、网络等。尝试仅使用单元测试和端到端测试来测试那些脆弱和有影响力的依赖项的实现。

1
作为一名测试人员,这更多地涉及到我在使用SpecFlow时的工作。你必须从BI的角度来看待它,并在编写Feature测试时像他们一样思考。这些测试需要让BI人员能够理解,以便作为与开发人员沟通的一种方式,后者将在Feature文件(步骤定义)的后端进行工作。 - MichaelF

3

不要直接用页面名称,而是描述它代表的内容,例如:

Scenario: Customers logs in successfully

  When I log in
  Then I should see an overview of ACME's top selling products

你可以直接针对底层 API 或模型进行测试,但是你这样做的次数越多,就越有可能会错过集成问题。一种方法是用少量的全栈测试和大量两个层之间测试来平衡事情。


那么,“当我在产品页面上时”变成“当我查看可用产品时”?少量的全栈测试就像http://code.google.com/p/ndddsample/source/browse/trunk/src/NDDDSample/test/NDDDSample.Tests/Scenarios/CargoLifecycleScenarioTest.cs? - Sergey Berezovskiy
对于端到端测试和低级别集成测试之间的平衡,如果您有好的建议,请点赞。测试越低级别,就越不容易因其他测试而变得脆弱,运行速度也更快,并且覆盖范围更广。但是,它们捕捉集成错误的可能性就越小。 - Merlyn Morgan-Graham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接