Fluency in Fluent Interfaces
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!