9

My spring-data-jpa backend has a class that populates the (test) database with a lot of test data. The class usese the spring data repositories to create entities. All my entities have a field annotated with @CreatedData and the corresponding @EntityListeners(AuditingEntityListener.class) annotation on the model class. This works fine so far. dateCreated is automatically set correctly.

But when running Junit test I sometimes need to create a (test) object with a dateCreated in the past. How can I archive this? Only via plain JDBC?

Robert
  • 1,238
  • 1
  • 19
  • 34

3 Answers3

3

I found a way that works for me (using plain JDBC):

First I create my domain objects for testing with spring-data-jpa:

MyModel savedModel = myRepo.save(myModel);

That automatically fills the "dateCreated" with timestamp of "now". Since I need creation dates in the past for testing I manually tweak them with plain JDBC:

@Autowired
JdbcTemplate jdbcTemplate;

[...]

// This syntax is for H2 DB.  For MySQL you need to use DATE_ADD
String sql = "UPDATE myTable SET created_at = DATEADD('DAY', -"+ageInDays+", NOW()) WHERE id='"+savedLaw.getId()+"'";
jdbcTemplate.execute(sql);
savedModel.setCreatedAt(new Date(System.currentTimeMillis() - ageInDays* 3600*24*1000);

Do not forget to also setCreatedAt inside the returned model class.

Robert
  • 1,238
  • 1
  • 19
  • 34
3

In case you are using Spring Boot, you can mock dateTimeProvider bean used in EnableJpaAuditing annotation. Spring Data uses this bean to obtain current time at the entity creation/modification.

@Import({TestDateTimeProvider.class})
@DataJpaTest
@EnableJpaAuditing(dateTimeProviderRef = "testDateTimeProvider")
public class SomeTest {

    @MockBean
    DateTimeProvider dateTimeProvider;

...

It is necessary to define actual testDateTimeProvider bean, but it won't be used at all, as you will use mock instead. You can write mockito methods afterwards as usual:

@Test
public void shouldUseMockDate() {

    when(dateTimeProvider.getNow()).thenReturn(Optional.of(LocalDateTime.of(2020, 2, 2, 0, 0, 0)));
    
   
   ... actual test assertions ...
0

I do not know exact test case which you are using, but i can see few solutions:

  • create a mock object, once the dateCreated is called return date month ago
  • maybe use in-mem db, populate it with date before test
  • go with AOP from the link provided in comments
pezetem
  • 2,393
  • 2
  • 18
  • 37
  • Thank you for the suggestions: MockObjects: I need hundrests entries each with different creation dates in my DB. InMemoryDB: That is what I am using. I populate it with my TestDataCreator.java I am creating my testdata in java (instead of plain sql in a data.sql file) because I need to juggle a lot of references between the test data entries. – Robert Feb 21 '17 at 18:27