Test Data Builders Refined
Last year, I blogged about Test Data Builders here and here. I still use them heavily in my unit tests for creating objects with test data. Heck, I also use this pattern for fluent interfaces in production code. Here is a simple example of this approach:
1: public class CustomerBuilder
2: {
3: public String _firstName = "Homer";
4: public String _lastName = "Simpson";
5:
6: public CustomerBuilder WithFirstName(String firstName)
7: {
8: _firstName = firstName;
9: return this;
10: }
11:
12: public CustomerBuilder WithLastName(String lastName)
13: {
14: _lastName = lastName;
15: return this;
16: }
17:
18: public Customer Build()
19: {
20: return new Customer(_firstName, _lastName);
21: }
22: }
This fluent builder class can then be used this way:
1: Customer customer = new CustomerBuilder()
2: .WithFirstName("Homer")
3: .WithLastName("Simpson")
4: .Build();
A while ago, Greg Young started a series of blog posts on DDDD (Distributed Domain-Driven Design), which I can highly recommend. Make sure to catch up now you still can because I think that he has a lot of stuff coming up, which I’m really looking forward to.
Anyhow, Greg had a couple of posts on fluent builders, which you can read here, here and here. I noticed an interesting approach in the way that the target object is built. Here is an example of this approach:
1: public class CustomerBuilder
2: {
3: public String _firstName = "Homer";
4: public String _lastName = "Simpson";
5:
6: public CustomerBuilder WithFirstName(String firstName)
7: {
8: _firstName = firstName;
9: return this;
10: }
11:
12: public CustomerBuilder WithLastName(String lastName)
13: {
14: _lastName = lastName;
15: return this;
16: }
17:
18: public Customer Build()
19: {
20: return new Customer(_firstName, _lastName);
21: }
22:
23: public static implicit operator Customer(
24: CustomerBuilder builder)
25: {
26: return builder.Build()
27: }
28: }
which results in the following usage:
1: Customer customer = new CustomerBuilder()
2: .WithFirstName("Homer")
3: .WithLastName("Simpson");
Adding an implicit cast operator to the builder class makes that its no longer required to explicitly call the Build method. I keep the Build method around for backwards-compatibility reasons or in case I ever need it again (violating YAGNI in the process, I know, I know). I find that adding the implicit cast operator adds to the readability of the fluent interface, don’t you agree?
Uncategorized






agree!