Saturday, December 20, 2008

Object Mocking in F# with Rhino Mocks

Near the end of Oct. 2008, I posted an entry entitled Mocking F#.  While that post may be helpful to some, others may be looking for an example of how to dynamically mock objects from tests written in F#.  This post will attempt to provide that example.  In addition, it will provide another example of a BDD approach using some of the functionality in SpecUnit (a previous example is here).

Since the types being tested have not changed from those provided in the Mocking F# post, I will not be re-posting them here. 

#light
namespace FSharpMockExample.Services.Specs
open FSharpMockExample.Services
open FSharpMockExample.Entities
open FSharpMockExample.Data
open NUnit.Framework
open SpecUnit
open Rhino.Mocks

[<TestFixture>]
[<Concern("Customer Balance Calculation")>]
type behaves_like_context_with_customer_balance_calculation() = 
    inherit ContextSpecification()
    [<DefaultValue(false)>]
    val mutable customerService : ICustomerService
    [<DefaultValue(false)>]
    val mutable mocks : MockRepository
    override this.Context () = 
        this.mocks <- new MockRepository()
        ignore None

[<TestFixture>]
[<Concern("Customer Balance Calculation")>]
type When_calculating_balance_with_starting_balance_of_fifty_and_ten_percent_discount() = 
    inherit behaves_like_context_with_customer_balance_calculation()
    override this.Because () = 
        this.mocks <- new MockRepository()
        let cAgs = [||]
        let customerDao = this.mocks.DynamicMock<ICustomerDao>(cAgs)
        let customer = new Customer(1, "XYZ Company", 50.00M)
        Expect.Call(customerDao.GetById(1)).Return(customer) |> ignore
        this.customerService <- new CustomerService(customerDao) 
    [<Observation>]
    member this.should_have_a_calculated_balance_of_forty_five() = 
        this.mocks.ReplayAll();
        this.customerService.CalculateBalaceWithDiscount(1, 0.1M).ShouldEqual(45M) |> ignore
        this.mocks.VerifyAll();


Wednesday, December 10, 2008

Behavior Driven Development (BDD) in F# with SpecUnit .NET

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.