Unable to get table autocreated in spring module integration test

Viewed 233

I have a parameters module in my project which other modules are dependent on. I'd like to write instegration tests for this module in separate manner. This module is a spring based one and has some db related logic, though db migration scripts are not available in this module since it is something that is out of its area of resposibility. By the way in-memory H2 instance is used for testing purposes.

What I'm trying to achieve is to make spring/hibernate create DB tables based on single @Entity class present in this module, it is called ParameterEntity.

It is defined like this:

@Entity
@Table(name = "SYSTEM_PARAMETERS")
public class ParameterEntity {
    @Id
    @Column(name = "id")
    private String id;
    @Column(name = "value")
    private String value;

    // accessors go here...
}

In my application-test.yml file I provide the following props:

spring:
  jpa:
    hibernate:
      ddl-auto: create
    database: h2
    show-sql: true

And define integration test class like this:

@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties
@EntityScan("path.to.package.where.parameter.entity.resides")
@ConstextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
@ActiveProfiles("test")
@TestInstance(Lifecycle.PER_CLASS)
public class ParametersIntegrationTest {
    @Autowired
    private ParameterWarden warden;
    
    @BeforeEach
    public void setUp() {
        warden.initialize();
    }

    @Configuration
    @ComponentScan("base.module.package")
    static class TestConfiguration {
        // here comes some test beans which will be used in testing purposes only
    }
}

In @BeforeEach method ParameterWarden class calls repository class which in turn make some calls to database to retrieve parameter entities from database and these calls fail because SYSTEM_PARAMETERS is missing.

Could anyone, please, let me know what am I missing here and how can I make spring or hibernate create table based on the entity present in my project. Even the place where I can debug this would be nice to know.
It seems like I need another magical thing that will trigger this functionality but I was unable to figure out what exactly I need.

Any help is really appreciated, thank you very much for your time!

p.s. I can not use @SpringBootTest annotation since this module uses only some spring features and is not a spring boot application itself. It is used as a dependecy in another spring boot applications.

1 Answers

Can you still use @DataJpaTest?

package com.test;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@DataJpaTest
@ContextConfiguration(classes = TestEntityRepository.class)
@TestPropertySource(properties = {
        "spring.jpa.hibernate.ddl-auto=create",
        "spring.datasource.platform=h2",
        "spring.jpa.show-sql=true"
})
@EnableAutoConfiguration
public class IntegrationTest {

    @Autowired
    TestEntityRepository testEntityRepository;

    @Test
    void testCreateRead() {
        var saved = testEntityRepository.save(new TestEntity("test"));

        Assertions.assertNotNull(saved);

        var read = testEntityRepository.findById(saved.getId());

        Assertions.assertNotNull(read);
    }
}

Where repository and entity in the com.test package are:

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TestEntityRepository extends CrudRepository<TestEntity, Long> { }
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@NoArgsConstructor
public class TestEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    private Long id;

    @Column
    private String attr;

    public TestEntity(String attr) {
        this.attr = attr;
    }
}

Dependecies used (through dependency management and Spring Boot BOM of version 2.3.4.RELEASE):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>


Alternatively, if you want to fully decouple tests from Spring you can use org.hibernate.tool.hbm2ddl.SchemaExport in some utility logic since that's what's really executing under the hood. I use this approach since my project requires some extra steps to setup the database, however, it might be too complicated for some use cases.

Related