How to compare new Date in unit test?

Viewed 144

I have service with method :

Entity entity = new Entity(new Date(), 1, 2L);
return entityRepository.save(entity);

And my test :

@Test
public void testSaveEntity() {
    Entity entity = new Entity(new Date(), 1, 2L);
    entityService.saveEntity(1, 2L);
    verify(entityRepository, times(1)).save(entity);
} 

If Entity equals() not compared Date then everything is all right but if compare Date then test throws out Argument(s) are different!

4 Answers

As I understand it is impossible to change the service and the entity. Then in such cases it is better to use ArgumentMatcher<> in Mockito.

Step 1 :

@AllArgsConstructor
public class EntityMatcher implements ArgumentMatcher<Entity> {

    private Entity left;

    @Override
    public boolean matches(Entity right) {
        return (left.getEventDate().getTime() - right.getEventDate().getTime() <= 1000));
    }
}

Here you ovverride equals which will be compare objects. mathces can be ovveride as you like. I think the difference in one second is enough.

Step 2:

verify(entityRepository).save(argThat(new EntityMatcher(new Entity(new Date(), 1, 2L))));

Other case : Most likely, in other tests, such a situation may arise that this entity will also need to be checked when

when(entityRepository.save(any(Entity.class))).thenReturn(new Entity(new Date(), 1, 2L));

You have 2 options:

Option 1: Use Clock class to control time

Instead of using new Date():

  • inject a Clock instance to your service
  • use its methods to retrieve current time
  • In your test code, use Clock.fixed to control current time

See Guide to the Java Clock Class

Option 1: Relax your matching requirements

Use Mockito ArgumentMatchers to relax mtching requirements - use any(YourEntity.class) to match any YourEntity, or write a custom argument matcher for your Entity.

You may be having an issue with the definition of your equals method. You should define under which circumstances two different Entities are considered equal:

Are two Entities equal only if their date value is within the same
millisecond or do we only care about seconds, minutes or days?

Similar to handling floating point values, this acceptable difference can be calculated similar to Calculating the difference between two Java date instances

Instead of relying on the equals method used in your solution:

verify(entityRepository, times(1)).save(entity);

you could try to capture the Argument and assert it in the next step as described in Verify object attribute value with mockito

ArgumentCaptor<Entity> argument = ArgumentCaptor.forClass(Entity.class);
verify(entityRepository, times(1)).save((argument.capture());
assertEquals(1, argument.getValue().getWhatever());
Related