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?
agree!
These information helps me consider some useful things, keep up the good work.
These information helps me consider some useful things, keep up the good work.
These information helps me consider some useful things, keep up the good work.