I have domain aggregate Employee
which uses builder pattern to set its fields during object construction. It has various lifecycle methods that mutate the state but no direct setters. It also has a validate() method which checks some conditions on the fields set by the builder and therefore can fail (throw exception) for multiple reasons.
The aggregate is somewhat like below:
public class Employee {
private String field1;
private String field2:
//say 10 fields
public static Builder builder() {
return new Builder();
}
public static class Builder {
// builder fields and methods
}
//public lifecycle methods
public void validate() {
if (field1 == null) {
//throw custom exception
}
if (field2 == null) {
//throw custom exception
}
// More condition checks on fields (not all are null checks)
}
}
Now my test class is organized as below:
public class EmployeeTest {
@Test
public void givenNewEmployee_IfField1IsMissing_thenThrowsException() {
//Setup
Employee testEmployee = Employee.builder()
.field2(nonNullValue)
//other fields
.build();
Assertions.assertThrows(CustomException.class, testEmployee::validate);
}
@Test
public void givenNewEmployee_IfField2IsMissing_thenThrowsException() {
//Setup
Employee testEmployee = Employee.builder()
.field1(nonNullValue)
//other fields
.build();
//Test
Assertions.assertThrows(CustomException.class, testEmployee::validate);
}
}
In the above, for each test case I have to build the whole Employee test object testEmployee
except one field in the build()
method. This makes my test cases clumsy and take many lines of code.
My question is:
Is there a way I can use to setup the testEmployee
object once and then set the individual fields to null in each of the test cases so that my tests are concise and doesn't require building the entire testEmployee
?
I am aware of @BeforeAll
and @BeforeEach
annotations for setting up tests. But since my Employee
class does not provide any setter I have no way to setup a one valid testEmployee
in @BeforeEach
and then set the individual fields to null in each of the test cases. So I need alternatives if available.
In @BeforeEach
create builder and fill all fields. Then store it.
In each test set field to null
, then build and validate.
Example:
class EmployeeTest {
Employee.Builder builder;
@BeforeEach
void init(){
builder = Employee.builder()
.field1("some value")
.field2("another value")
}
@Test
void testField1Value() {
Employee e = builder.field1(null).build();
e.validate();
}
}
Alternatively you can create toBuilder
method. Then you can do employee.toBuilder().fieldq(null).build().validate()
.