Creating a Hierarchical Test Data Builder using Generics

At my current client, we had a situation where we needed to write JUnit tests for REST services which used a complex object hierarchy. Creating these objects manually proved to be very tedious, so having learned about using the Test Data Builder Pattern we wanted to make the builders match the object hierarchy.

Here’s an small example of what that hierarchy looks like:

Here’s what the AbstractRelationship Java code looks like:

Because this hierarchy is generated by JAXB, there are no generics in it, so even though as a rule, RelationshipType1 takes RoleType1 as the requester and RoleType2 as the provider, they show up as AbstractRole in the IDE code assist.

One possible solution is to use XML that is generated by the service that we could unmarshal with JAXB. While that worked in some cases, most of the time it ended up being to much of a hassle to keep the XML files up to date when changes were made to schema or if we needed to make changes to the JUnit tests. Plus the services were not ready when we were writing these tests and trying to write the XML with all its complexities was way too much. So we turned to the builders.

One of the things we wanted to do with the builders is make it so that those who used them didn’t worry about the rules of which roles belong to which relationships, this was done by using generics.

Here’s what the builders look like, first the Builder interface:

Let’s take a look at the AbstractRoleBuilder:

A little explanation is now in order. The goal of this builder hierarchy is to match that of the JAXB generated hierarchy, so the methods that are in the abstract JAXB classes have their matching builder methods in the abstract builder class. The “B” generic type (for Builder) is there so that when “withAbstractRoleID” is called from RoleType1Builder for example, it returns itself rather than AbstractRoleBuilder, which follows the pattern.

Here’s what RoleType1Builder would look like:

Quick note: the link provided above provides more of a “true” builder pattern in that the build method is where the object being created is actually built. I deviated from this by using an “instance” variable for the object being built and created it in the constructor; then the fields on it would get changed by calling the builder methods. I found this to be easier than keeping separate variables for each field and it cut down on the amount code. Most of the time either style works, but in order for the below code to work we’ll have to use the “instance” method.

Next up is the AbstractRelationshipBuilder:

Here we use the two role builders to add the requester and provider roles (typed as “R” and “P”). In this case, since the actual instance variable will be on the concrete type, we use the build method to call the “setRequester” and “setProvider” methods since those are on the AbstractRelationship object. Once again we use the “B” type to define the builder.

Last up is the RelationshipType1Builder:

When you set the requester and provider on the above instance, you’ll need to know which roles belong to which relationships because an IDE code assist on both will show AbstractRole. So as you can see from above, the builder is typed to RelationshipType1, the “B” type is RelationshipType1Builder, and the “R” and “P” types are RoleType1Builder, and RoleType2Builder respectively. Now lets talk a look at how we would use the builder:

Now if we use code assist, it will show the correct builder type for the roles. While I used “TypeN” examples here, in my actual project there were 6 relationship types and 10 role types where all but one or two used different type roles for the requester and provider. And in the role hierarchy there was an additional level that I didn’t put in here. Having these builders made writing tests much easier.

About the Author

Object Partners profile.
Leave a Reply

Your email address will not be published.

Related Blog Posts
Building Better Data Visualization Experiences: Part 1 of 2
Through direct experience with data scientists, business analysts, lab technicians, as well as other UX professionals, I have found that we need a better understanding of the people who will be using our data visualization products in order to build them. Creating a product utilizing data with the goal of providing insight is fundamentally different from a typical user-centric web experience, although traditional UX process methods can help.
Kafka Schema Evolution With Java Spring Boot and Protobuf
In this blog I will be demonstrating Kafka schema evolution with Java, Spring Boot and Protobuf.  This app is for tutorial purposes, so there will be instances where a refactor could happen. I tried to […]
Redis Bitmaps: Storing state in small places
Redis is a popular open source in-memory data store that supports all kinds of abstract data structures. In this post and in an accompanying example Java project, I am going to explore two great use […]
Let’s build a WordPress & Kernel updated AMI with Packer
First, let’s start with What is an AMI? An Amazon Machine Image (AMI) is a master image for the creation of virtual servers in an AWS environment. The machine images are like templates that are configured with […]