How to enable JPA auditing with SpringBootTest?
Asked Answered
E

0

9

I want to write integration tests for my RestAPI endpoints, and I'm struggling with @EnableJpaAuditing. I want some of my entities to be audited by Spring, so I've created the following configuration class:

@Configuration
@EnableJpaAuditing
public class PersistenceAuditConfiguration {

}

Which I import into my main application config:

@ServletComponentScan
@SpringBootApplication
@Import(PersistenceAuditConfiguration.class)
public class TMTWebApplication {

    public static void main(String[] args)  {
        SpringApplication.run(TMTWebApplication.class, args);
    }
}

Also, I have an abstract base class for all entities that I want to be audited:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true)
public abstract class AuditableEntity extends EpicPojo implements Serializable {

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at", nullable = false, updatable = false)
@CreatedDate
private Date createdAt;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated_at", nullable = false)
@LastModifiedDate
private Date updatedAt;

    //...and so on

}

In my application.yml, I have set the following properties:

spring:
    datasource:
        url: jdbc:postgresql://localhost:5432/tmt
        username: whoever
        password: whatever
        driver-class-name: org.postgresql.Driver
    flyway:
        baselineOnMigrate: true
        locations: classpath:db/migration
    jpa:
        hibernate:
            ddl-auto: update
        generate-ddl: true
        properties:
            hibernate:
                dialect: org.hibernate.dialect.PostgreSQL10Dialect
                jdbc:
                    lob:
                        non_contextual_creation: true

This way, I can omit the auditing fields (columns) in my Flyway migration scripts. When I start the application normally on an empty database, the auditing columns created_at and updated_at are being created for every entity that inherits from AuditableEntity.

Now, I want to run my integration test using the @SpringBootTest annotation, so I am expecting the whole application context to be started pretty much the same way. Unfortunately, this is not the case. I am using Zonky's embedded Postgres for tests since I have some JSONB datatypes. Setting it up worked seamlessly, but unfortunately the auditing fields aren't created. My test class looks like this:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureEmbeddedDatabase
@FlywayTest
@Import(PersistenceAuditConfiguration.class)
public class AuthController_IntegrationTest {

    //... testy-testy, test, test

}

The first test will insert (register) a new user to my audited users table and return it, but it fails due to the following exception:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is 
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; 
nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet

[stack trace omitted]

Caused by: org.postgresql.util.PSQLException: ERROR: column roleentity0_.created_at does not exist

I've found a lot of similar issues, but most dealt with @DataJpaTest and not @SpringBootTest (at this point I don't want to test different layers separately). According to different threads and issues I could find, I've also tried the following:

  • @EnableJpaAuditing directly on TMTWebApplication config class, which was the first and original way prior to writing integration tests.

  • @EnableJPAAudidting directly on my test class, which led to a BeanDefinitionOverrideException. After I reluctantly allowed bean overriding, I ran into the above exception again (created_at does not exist).

I can see that there are issues from this and this thread on Github, but I don't yet understand the underlying design of Spring for this particular configuration, and the documentation didn't really help either. Please note: I've asked a similar question to this issue yesterday, but I deleted it. I suspected that it had something to do with Zonky's embedded Postgres instance not understanding the application properties, but I guess that was wrong, so I had to rephrase it to focus on Spring only. I guess, I am missing the forest for all the trees around here, so if someone could point me to the right tree, I'd highly appreciate it. Thanks in advance!

Ether answered 5/6, 2020 at 8:55 Comment(2)
Do we have any progress with this?Fivepenny
That error is a little bit suspicious. Seems like it's complaining about the table. Like spring wants to fill out that column but it doesn't exist in the db table. For the sake of it, can you check this pls?Taurus

© 2022 - 2024 — McMap. All rights reserved.