Why We Need A Builder Pattern For Our Test Data

Why we need a Builder Pattern for our test data

Properly testing Apex code is a necessary and important element of Salesforce development. To do so requires building test data that grows in complexity with the code you are testing.

The Force.com platform gives us a pretty simple way to create sObject Data for Unit Tests. With the dynamic constructors that sObjects are equipped with, we can create records with populated fields.

How is it then that so many people struggle to create good test data?

This pattern does not hide the complexity of the test data creation from the actual test method / class:

Order__c someOrder = new Order__c(
	OrderNumber__c = '12345', 
	OrderSummary__c = 'Some Summary'
);
insert someOrder;

OrderItem__c someItem = new OrderItem(
	Order__c = someOrder.Id, 
	Item__c = 'Table'
);
insert someItem;

ShippingAddress__c someAddress = new ShippingAddress__c(
	Order__c = someOrder.Id, 
	Street__c = 'Some Street', 
	City__c = 'Some City', 
	State__c = 'Some State', 
	Country__c = 'Some Country'
);
insert someAddress;

Now, there are several issues with the above pattern:

  • First off, we need to know all this information for every test method or class we want to create this data for.
  • We also need to know which fields need to be populated for our initial insert.
  • As well as which fields we need for our actual test.

So at some point, we start to abstract this knowledge away to make our tests clearer and more readable.

This is where the Factory Pattern comes in…

The Factory Pattern is used inside the Force.com community to create abstract test data in an easy, convenient and re-usable way. For example, the above test data could be generated by one line:

TestDataFactory.createSomeOrder();

Seems nice enough, right?

It is.

But now let’s take this pattern one step further. Let’s create a more specific test data:

  • [ ] an order with specific items and specific addresses. What do we do?
TestDataFactory.createSomeOrder();
TestDataFactory.createTableAndChairsOrder();
TestDataFactory.createTableAndChairsOrderWithGermanShippingAddress();
TestDataFactory.createChairsAndLampsOrder();

Over time, our factory classes tend to get bloated, messy and very hard to maintain to a high coding standard.

In the example above, what if we want to create an order with tables, chairs and lamps with a generic address? -> We again create a new static method with specific naming. What happens when our test breaks? And how do we find out quickly which value the OrderSummary__c field has for a specific test? -> It is likely we have to dig into the factory class itself to find out. What if we need to change this value just for one of our new tests?

This is an awful state for our code. The harder it is to understand unit tests, the slower it is to update them and write new ones. This leads to poorly tested code and projects that fail to meet deadlines and requirements.

It feels like our tests drag us down and slow us down.

How can we avoid this terrible state?

In Part Two of our Builder Pattern blog series, we’ll see how the Builder Pattern can clean up some of the issues outlined above.

#blog #builderPattern #mavens