Implementing the "Overdue book" feature

The scenario to implement is the following:
Scenario: Overdue book after 28 days
	Given the user has borrowed a book
	And 29 days have passed
	And the fine for one overdue book is 100 DKK
	Then the user has overdue books
	And the user has to pay a fine of 100 DKK
To make this work, the library application needs a reference to a DateServer object, that we can manipulate.

LibraryApp has a field dateServer. The method getDate() in class DateServer is implemented by returning a new GregorianCalendar object, i.e., "return new GreogorianCalendar()". This object represents the current date and time. Here is the skeleton LibraryApp.java file, showing the use of the DateServer class.

During testing, the actual DataServer is going to be replaced by a so called "mock" object. A mock object is a "fake" or a "stub" replacing the original object, and which allows the programmer to take over control of what the object does. In our case, we want to have the control of the current date, i.e., being able to, e.g., advance the current date by 29 days to make books overdue. For this, we are using the Mockito framework. Below is information on how to install Mockito. This is a very nice and easy to use framework. You just "import static org.mockito.Mockito.*", then you can easily create your own mock objects. For example, to create a field for DateServer using a mock DateServer, you write:

DateServer dateServer = mock(DateServer.class);
This creates a mock object, that understands the same method as the DateServer, but that one can control. For example, one can define the result of the method getDate() by:
when(dateServer.getDate()).thenReturn(aGregorianCalendar)
Next time getDate() is called on the dateServer mock, the value of the variable aGregorianCalendar is returned.

Now it is easy to advance the date by 29 days:

Calendar currentDate = dateServer.getDate();
// Important: we need to create a new object,
// otherwise, the old calendar object gets changed,
// which suddenly changes the date for objects 
// using that old calendar object
Calendar nextDate = new GregorianCalendar();
nextDate.setTime(currentDate.getTime());
nextDate.add(Calendar.DAY_OF_YEAR, 29);
when(dateServer.getDate()).thenReturn(nextDate)

How does the library application know about the mock date server? Similar as with the problem of error messages, we use a MockDateHolder class, which coordinates the use of the mock DateServer across step definitions. When the MockDateHolder class is created, we pass it a LibraryApp object via dependency injection. The MockDateHolder does not need to store the LibraryApp object, but sets its date server to the mock version of the date server:

public MockDateHolder(LibraryApp libraryApp) {
	GregorianCalendar calendar = new GregorianCalendar();
	when(dateServer.getDate()).thenReturn(calendar);
	libraryApp.setDateServer(dateServer);
}

Here are the step definitions in the UserSteps class, the BookSteps class, and the TimeStep class for the overdue scenario above, the complete MockDateHolder class and the DateServer class..


On to Mocking the e-mail server Part of Assignment Week 3
Hubert Baumeister
April 23, 2018