BDD Overview:
Behavior Driven Development (BDD) is a process that evolved from Test Driven Development (TDD). The differences are subtle and primarily focus on removing communication related confusion (Dan North-the founder of BDD-provides a nice introduction
here).
http://behaviour-driven.org/ describes BDD as a convergence of TDD and Domain-Driven Design (DDD) - (A good introduction to DDD can be found on
Hanselminutes show #140 with Rob Conery). One of the foundations of DDD is the concept of removing complexity by creating a common language to help bridge the gap between business and technology . This common language is known as the ubiquitous language.
The first thing that BDD does to help accomplish the goal of a ubiquitous language is remove the central focus on "tests". Generally, when the word "Test" is mentioned to a business minded person, they will immediately think about a quality assurance process that is situated near the end of a project plan. By changing the termonology from "Test" to "Specification", the focus changes to something done near the beginning of the project plan that defines and drives the development of the solution. This small focal shift can make a big difference in how the project is driven.
BDD also has advantages for developers. When specifications are documented in code, that code is more likely to accomplish the business goals, be easier to understand, and be much more maintainable over the life of the solution. In addition, the specifications written to drive the development can then be used to prove that the final product meets all of the business requirements.
There are many additional benefits to BDD. For additional information, check out http://behaviour-driven.org/.
BDD in F#:
After reading
Starting with BDD vs. TDD, I decided to checkout
SpecUnit .NET. I pulled down the sample application (i.e. Banking) and did a quick and dirty port to F#.
Specification:
#light
namespace BankingFSharp.Specs
open NUnit.Framework
open SpecUnit
open BankingFSharp
[<TestFixture>]
[<Concern("funds transfer")>]
type behaves_like_context_with_from_account_and_to_account() =
inherit ContextSpecification()
[<DefaultValue(false)>]
val mutable fromAccount : Account
[<DefaultValue(false)>]
val mutable toAccount : Account
override this.Context () =
this.fromAccount <- new Account(1m)
this.toAccount <- new Account(1m)
ignore None
[<Concern("funds transfer")>]
type when_transferring_between_two_accounts() =
inherit behaves_like_context_with_from_account_and_to_account()
override this.Because () =
this.fromAccount.Transfer(1m, this.toAccount) |> ignore
[<Observation>]
member this.should_debit_the_from_account_by_the_amount_transferred () =
this.fromAccount.Balance.ShouldEqual(0m) |> ignore
[<Observation>]
member this.should_credit_the_to_account_by_the_amount_transferred () =
this.toAccount.Balance.ShouldEqual(2m) |> ignore
Code:
#light
namespace BankingFSharp
open System
type Account = class
val mutable balance: decimal;
new (balance) = {balance = balance}
member this.Balance
with get() = this.balance and set(v) = this.balance <- v
member this.Transfer (amount,toAccount:Account) =
if amount > this.balance then
let errorMessage = String.Format("Cannot transfer ${0}. The available balance is ${1}.", amount, this.balance)
failwith errorMessage
else
this.Balance <- this.balance - amount
toAccount.Balance <- toAccount.Balance + amount
end
Result:
When NUnit was opened, it was exciting to see how much of the story was now being conveyed through the tests. While this is not completely ubiquitous, the output (i.e. " when transferring between two accounts" "should create the to account by the account transferred") is pretty close to what one would see in a requirements document.
Conclusion:
BDD is a positive step toward closing the gap between business and technology. Tools such as SpecUnit .NET make this process easier and it was refreshing to see out of the box support for F#. As more developers start to see the benefits of TDD and BDD, we will see the infamous divide between business and technology finally start to close.