Scott Hanselman's recent post about the
Daily Source Code 14 - Fluent Interface Edition got me to think more on
fluent interfaces and a previous post of mine on
ObjectMother versus Test Data Builders. Also, it comes to mind in regards to DSLs, both internal and external that has me intrigued. Partially due to my latest involvement with Ruby and F#.
Test Data Builder Example
So, let's revisit that simple example:
public class ClaimBuilder
{
private DateTime claimDate;
private Provider provider = ProviderBuilder.StartRecording().Build();
private Recipient recipient = RecipientBuilder.StartRecording().Build();
private ClaimLineCollection claimLines = ClaimLinesBuilder.StartRecording.Build();
public static ClaimBuilder StartRecording()
{
return new ClaimBuilder();
}
public ClaimBuilder WithClaimDate(DateTime claimDate)
{
this.claimDate = claimDate;
return this;
}
public ClaimBuilder WithProvider(Provider provider)
{
this.provider = provider;
return this;
}
public ClaimBuilder WithRecipient(Recipient recipient)
{
this.recipient = recipient;
return this;
}
public ClaimBuilder WithClaimLines(ClaimLineCollection claimLines)
{
this.claimLines = claimLines;
return this;
}
public static implicit operator Claim(ClaimBuilder builder)
{
return new Claim(builder.claimDate, builder.provider, builder.recipient, builder.claimLines);
}
}
As you may note I changed the Build method from the previous post to an implicit operator to save me some coding time when it comes to my builders. This is one of the very very few places where I'd recommend using this operator. Anyhow, then we'd have the calling code to look similar to this for my unit tests.
Claim claim = ClaimBuilder.StartRecording()
.WithClaimDate(new DateTime(2008, 1, 1))
.WithProvider(ProviderBuilder.StartRecording()
.WithName("Robert", "Jones")
.WithAddress(AddressBuilder.StartRecording()
.WithStreetAddress("1800 28th St, NW")
.WithCity("Washington")
.WithState("DC"))))
.WithRecipient(RecipientBuilder.StartRecording()
.WithName(James", "Smith")
.WithAddress(AddressBuilder.StartRecording()
.WithStreetAddress("1210 14th St, SE",)
.WithCity("Washington")
.WithState("DC"))))
.WithClaimLines(ClaimLinesBuilder.StartRecording()
.WithClaim("00308-1")));
This is truly powerful here to make it make sense to the reader instead of the usual black box ObjectMother approach. When building my entity objects for test, this is the main approach I use.
Other Examples
Scott Bellware has introduced the
Behavior Driven Development NUnit Extensions which makes heavy use of fluent interfaces. With my deeper dive into BDD, this has been very helpful.
Dave Laribee also has me on the kick as well, so lots of thanks to them for pointing me in the right direction, although some may disagree with their directions. But that's for another time and another post.
Jeremy Miller also has fluent interfaces on his
StructureMap IOC container project. Some new parts with registration will be coming up with his new release of version 2.5 as noted
here.
Of course I can keep rattling on with others like NHibernate and the ICriteria, Castle Windsor's fluent registration interfaces and so on. The list goes on! Very cool stuff coming out lately... Until next time!