Apply TDD to Behavioral Domain Object
Now that you understand the process, use it to implement a behavioral domain object that uses an EmployeeDao to accomplish your high-level goal of "Raise Salaries to Baseline." In the process you'll learn about how Unitils integrates EasyMock.
The IEmployeeManager interface defines the following method signatures:
public void raiseSalariesToBaseline(String title, BigDecimal baseline);
public void setEmployeeDao(IEmployeeDao employeeDao);
One of the methods is simply a setter, but the other deserves some elaboration. The most important behavior of raiseSalariesToBaseline is that it actually raises salaries where appropriate. Create an executable specification in EmployeeManagerTest for this behavior by first setting up a mock IEmployeeDao:
@Mock
@InjectIntoByType
private IEmployeeDao employeeDao;
@TestedObject
private IEmployeeManager employeeManager;
Unitils automatically creates mock objects for fields annotated with @Mock, and it will use the setEmployeeDao method in your implementation to dependency inject automatically because you also included @InjectIntoByType. The @TestedObject indicates the instance of the class you're designing, and the target of all injections.
Now implement the actual behavior test, which is called raisesSalaries:
@Test
public void raisesSalaries()
throws DataAccessException
{
expect(employeeDao.findEmployeesByTitle(RAISE_TITLE))
.andReturn(newEmployeeFixture());
List<Employee> raisedEmployees = newEmployeeFixture();
raisedEmployees.get(1).setSalary(RAISE_BASELINE);
raisedEmployees.get(2).setSalary(RAISE_BASELINE);
employeeDao.saveEmployees(refEq(raisedEmployees.subList(1, 3),
ReflectionComparatorMode.LENIENT_ORDER));
expectLastCall();
EasyMockUnitils.replay();
employeeManager.raiseSalariesToBaseline(RAISE_TITLE, RAISE_BASELINE);
}
Note the use of refEq(), which is related to the Unitils ReflectionAssert class mentioned earlier. This method allows you to assert that saveEmployees gets called with a list equal to the salary-adjusted one you create in your test. Unitils uses reflection to spider all the members of each list and make sure their bean properties are equal.
It's important to note that you call newEmployeeFixture() twice. If you tried to modify the instance of your fixture returned by the mocked findEmployeesByTitle, refEq() would always succeed regardless of raiseSalariesToBaseline's behavior because EasyMock simply stores a pointer for any objects you provide in the expectations. So modifying a collection after setting an expectation with it invalidates the expectation.
For an implementation of IEmployeeManager, check out EmployeeManager in the project example.
Unitils Eases Test-Driven Design
One of the hurdles of test-driven design is the effort it takes to effectively isolate classes. Unitils goes a long way toward overcoming this issue by orchestrating packages like JUnit, DBUnit, and EasyMock, and making tests very concise and easy to write. I hope this article inspires you to try out TDD and Unitils on your next project. It's a combination that's led me to more satisfying development experiences.