If you've ever written unit tests in Java for a service layer, you probably know how quickly your test code can get cluttered with countless mock helper methods. Especially when you're mocking objects with several fields — it gets repetitive and hard to read.
Let me show you how switching to a Mock Builder Pattern can clean up your test suite and make your life a whole lot easier.
The Problem with Traditional Mocking
Here’s a simple UserValidator
that validates a list of users:
public class UserValidator {
public void validateUsers(List users) {
usersShouldBeAdults(users);
namesAndSurnamesShouldStartWithUpperCase(users);
usersShouldBeFromEurope(users);
}
// ... methods omitted for brevity ...
}
Your User
object might look like this:
@Getter
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class User {
UUID id;
String name;
String surname;
String country;
int age;
}
When it’s time to test, you might reach for helper methods like:
private User getUserWithAge(int age) { ... }
private User getUserWithAgeAndName(String name, int age) { ... }
private User getUserWithAgeAndNameAndSurname(String name, String surname, int age) { ... }
private User getFullUser(String name, String surname, String country, int age) { ... }
That’s fine at first... but it quickly spirals into a mess of methods just to cover all combinations of fields. Not great.
✅ Enter the Mock Builder Pattern
Instead of creating dozens of helpers, let’s use a single, flexible mock builder using Lombok’s @Builder
:
@Builder(builderMethodName = "user")
private static User getUserBuilder(
String name,
String surname,
String country,
Integer age
) {
User user = mock(User.class);
if (nonNull(name)) given(user.getName()).willReturn(name);
if (nonNull(surname)) given(user.getSurname()).willReturn(surname);
if (nonNull(country)) given(user.getCountry()).willReturn(country);
if (nonNull(age)) given(user.getAge()).willReturn(age);
return user;
}
Now, your tests become elegant and readable:
val users = List.of(
user().name("Alice").surname("Smith").country("France").age(30).build(),
user().name("Bob").surname("Brown").country("Germany").age(25).build()
);
You specify only the fields you need. No more boilerplate, no more bloated test classes.
Test Case Side-by-Side
Without Mock Builder
val users = List.of(
getUserWithAgeAndNameAndSurname("Jason", "born", 30),
getUserWithAge(21)
);
✅ With Mock Builder
val users = List.of(
user().name("Jason").surname("born").age(30).build(),
user().age(21).build()
);
🛠️ When to Use It
- Your objects have optional or many fields
- You're mocking with Mockito
- You want cleaner, DRY test code
- You hate writing getUserWithXAndY() for the 10th time
🔗 Code Sample
The full example is available here GitHub mock builder project.
Happy testing! 🧪