Sometimes, your need to create data structure for your test that might take a lot of line and introduce noise. In golang we don't have method overload or even constructors as some other language have. This means most of the time, we end up building our data using directly the struct expression, as below.

node := & Node { Name : "carthage" , Hostname : "carthage.sbr.pm" , Platform : Platform { Architecture : "x86_64" , OS : "linux" , }, }

Let's imagine we have a Validate function that make sure the specified Node is supported on our structure. We would write some tests that ensure that.

func TestValidateLinuxIsSupported ( t * testing.T ) { valid := Validate (& Node { Name : "carthage" , Hostname : "carthage.sbr.pm" , Platform : & Platform { Architecture : "x86_64" , OS : "linux" , }, }) if ! valid { t . Fatal ( "linux should be supported, it was not" ) } } func TestValidateDarwinIsNotSupported ( t * testing.T ) { valid := Validate (& Node { Name : "babylon" , Hostname : "babylon.sbr.pm" , Platform : & Platform { Architecture : "x86_64" , OS : "darwin" , }, }) if valid { t . Fatal ( "darwin should not be supported, it was" ) } }

This is quickly hard to read, there is too much noise on that test. We setup a whole Node struct, but the only thing we really intend to test is the Platform.OS part. The rest is just required fields for the function to correctly compile and run.

This is where test builders (and builders in general) comes into play. In Growing Object-Oriented Software Guided by Tests, the Chapter 22 "Constructing Complex Test Data" is exactly about that and guide us through the why and the how of these builders. The examples in the book are in java and uses wisely the object-oriented nature of the language. Here is an example from the book.

Order order = anOrder () . from ( aCustomer (). with ( anAddress (). withNotPostCode ())) . build ()