7

What would the junit test be when i have the following method:

@Override
public void saveLastSuccesfullLogin(final User user) {
    gebruiker.setLastLogin(new Date());
    storeUser(user);
}

submethode storeUser:

@Override
public void storeUser(final User user) {
    EntityManager em = emf.createEntityManager();

    em.getTransaction().begin();
    em.merge(user);
    em.getTransaction().commit();

    em.close();
}

The problem i have is the date, being set for the entity user and then stored. Im using junit and easymock.

Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
A.Khan
  • 73
  • 1
  • 3

4 Answers4

4

Try pulling the new Date() into a method with default access specifier like below

@Override
public void saveLastSuccesfullLogin(final User user) {
    gebruiker.setLastLogin(getDate());
    storeUser(user);
}
Date getDate() {
    return new Date();
}

In your test class override the class as below using a mock or stubbed date.

<ClassUnderTest> classUnderTest = new <ClassUnderTest> () {
  @Override 
  Date getDate() {
    return mockDate;
  } 
}

In this way you can assert the date value easily as it is going to be stubbed out.

Vinod R
  • 1,218
  • 10
  • 13
  • 2
    instead of overriding with anonymous class I would use [Mockito's partial mock](http://blog.javabien.net/2009/06/21/mockitos-partial-mocks-testing-real-objects-just-got-easier/). So it would be ClassUnderTest t = spy(new ClassUnderTest()); when(t.getDate()).thenReturn(DATE_MOCK); – Saulius Šimčikas Mar 27 '14 at 13:44
3

What's the problem with the Date? That you don't know what it is to assert later? A few alternatives:

  1. Pass the date into the method
  2. Create a factory to get the current date/time so you can mock it out
  3. Assert the date within a threshold of correctness
Jeanne Boyarsky
  • 12,156
  • 2
  • 49
  • 59
0

You can also create a getDate method, and a date static var:

    private static Date thisDate = null;

    @Override
    public void saveLastSuccesfullLogin(final User user) {
        gebruiker.setLastLogin(getDate());
        storeUser(user);
    }

    public Date getDate() {
        if(thisDate != null) return thisDate;
        return new Date();
    }

    public void setDate(Date newDate) {
        thisDate = newDate;
    }

Then in your test method, you can go ahead and call setDate to control what date you will get.

k.chao.0424
  • 1,191
  • 10
  • 11
0

There is also a more "enterprise" approach that may be used where Dependency Injection is available (like in EJB, Spring etc.).

You can define an interface, for example TimeService and add e method that returns the current date.

  public interface TimeService {
    Date getCurrentDate();
  }

You can implement this to return new Date() and use it like this:

  gebruiker.setLastLogin(timeService.getCurrentTime());

This will obviously be very easy to test because you can mock the TimeService. Using EasyMock (just an example), this might be:

  Date relevantDateForTest = ...
  expect(timeService.getCurrentTime()).andReturn(relevantDateForTest);
  replay(timeService);

Using the TimeService throughout the entire code and never using new Date() is a pretty good practice and has other advantages as well. I found it helpful in a number of occasions, including manual functional testing of features that would activate in the future. Going even further, the system time may be retrieved from an external system thus making it consistent across clusters etc.

Neovibrant
  • 747
  • 8
  • 16
  • I wrote a more detailed [post here](http://larselrund.com/2011/08/05/junit-with-new-date/) for those that wish to read more about using the separate service for retrieving the current date. – Neovibrant Aug 05 '11 at 16:27