行为驱动开发(Behavior-Driven Development, BDD)的概念来自于测试驱动开发,强调使用DSL(Domain Specific Language,领域特定语言)描述用户行为,定义业务需求,是需求分析人员、开发人员与测试人员进行沟通的有效方法。DSL是一种编码实现,相比自然语言更加精确,又能以符合领域概念的形式满足所谓“活文档(Living Document)”的要求。可以说,行为驱动开发将编码实现与业务行为描述***地结合起来,走出了一条业务分析人员、开发人员与测试人员都能接受的中庸之道。
行为驱动开发的核心在于“行为”。当业务需求被划分为不同的业务场景,并以“Given-When-Then”的形式描述出来时,就形成了一种范式化的领域建模规约。编写领域特定语言的过程,其实就是不断发现领域概念的过程。因此,采用BDD进行开发,最重要的产出不是可以自动运行的验收测试,而是它提供了团队交流的平台,并在其约束之下完成了领域建模。由于团队的不同角色都参与了这个过程,就保证了领域模型的一致性与准确性。
在进行行为驱动开发时,需要避免两种错误的倾向:
- 从UI操作去表现业务行为
- 描述技术实现而非业务需求
例如,我们要编写“发送邮件”这个业务场景,可能会写成这样:
- Scenario: send email
- Given a user "James" with password "123456"
- And I sign in
- And I fill in "mike@dddpractice.com" in "to" textbox
- And fill in "test email" in "subject" textbox
- And fill in "This is a test email" in "body" textarea
- When I click the "send email" button
- Then the email should be sent sucessfully
- And shown with message "the email is sent sucessfully"
该业务场景描写的不是业务行为,而是用户通过UI进行交互的操作流程。这种方式实则是让用户界面捆绑了你对领域行为的认知。准确地说,这种UI交互操作并非业务行为,例如上述场景中提到的button与textbox控件,与发送邮件的功能并没有关系。或许换一个UI设计,使用的控件又完全不同了。
那么换成这样的写法呢?
- Scenario: send email
- Given a user "James" with password "123456"
- And I sign in after OAuth authentification
- And I fill in "mike@dddpractice.com" as receiver
- And "test email" as subject
- And "This is a test email" as email body
- When I send the email
- Then it should connect smtp server
- And all messages should be composed to email
- And a composed email should be sent to receiver via smtp protocal
该场景的编写暴露了不必要的技术细节,如连接到smtp服务器、消息组合为邮件、邮件通过smtp协议发送等。对于BDD而言,场景应该关注于做什么(what),而不是怎么做(how)。如果在业务分析过程中,纠缠于技术细节,就可能导致我们忽略了业务价值。在业务建模阶段,业务才是重心,不能舍本逐末。
那么,该怎么写?当我们使用DSL编写业务场景时,不要考虑任何UI操作,甚至需要抛开业已设计好的UI原型,也不要考虑任何技术细节。在编写好业务场景之后,可以验证:如果我们更换了UI设计,调整了UI布局,是否需要修改业务场景?同理,如果我们改变了技术实现方案,是否需要修改业务场景?如下场景采用业务行为的形式编写:
- Scenario: send email
- Given a user "James" with password "123456"
- And I sign in
- And I fill in a subject with "test email"
- And a body with "This is a test email"
- When I send the email to "Mike" with address "mike@dddpractice.com"
- Then the email should be sent sucessfully
我们要将DSL描述的场景视为一种可读的需求规格(Specification),通过它准确地表现领域知识,就可以帮助我们提炼出隐含的领域概念。例如:
- Scenario: validate the given date for reporting period
- Given the reporting period as prior 13 month to report month
- And the reporting month is "April 2018"
- When user choose the "April 2017"
- Then validation result is true
- When user choose "March 2017"
- Then validation result is false
场景描述中的ReportingPeriod蕴含了与财务报表相关的领域知识,即有效报表周期为13个月,ReportingPeriod自身应该履行验证给定日期是否有效的职责。
【本文为51CTO专栏作者“张逸”原创稿件,转载请联系原作者】