Настроить конкретную базу данных в памяти для тестирования в Spring

Как настроить приложение Spring Boot таким образом, чтобы при запуске модульных тестов оно использовало базу данных в памяти, например H2/HSQL, но при запуске приложения Spring Boot оно будет использовать производственную базу данных [Postgre/MySQL]?

8 ответов

Решение

Для этого можно использовать пружинные профили. Это было бы определенным образом:

Иметь файлы свойств среды:

application.properties:

spring.profiles.active: dev

application-dev.properties

spring.jpa.database: MYSQL
spring.jpa.hibernate.ddl-auto: update

spring.datasource.url: jdbc:mysql://localhost:3306/dbname
spring.datasource.username: username
spring.datasource.password: password

application-test.properties

spring.jpa.database: HSQL

И драйверы MySQL и H2 в pom.xml, как это:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <scope>test</scope>
</dependency>

И последнее, но не менее важное: аннотируйте тестовые классы с помощью @ActiveProfiles("test"),

Другой подход заключается в добавлении аннотации @AutoConfigureTestDatabase тебе тестовый класс. Мои тесты обычно выглядят так:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
public class MyRepositoryTest {

    @Autowired
    MyRepository repository;

    @Test
    public void test() throws Exception {
        // Tests...
    }
}

С магией @SpringBootTest вам просто нужно выполнить следующие два изменения.

  1. Добавить тестовую зависимость h2 в pom.xml
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>
  1. Использовать @ AutoConfigureTestDatabase
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MySpringBootApplication.class)
@AutoConfigureTestDatabase
public class SpringBootTest{

    @Autowired
    private RequestRepository requestRepository;
}

Теперь все весенние jpa bean/ репозитории, используемые в тесте, будут использовать h2 в качестве резервной базы данных.

2019-04-26 13: 13: 34.198 ИНФОРМАЦИЯ 28627 --- [ main] beddedDataSourceBeanFactoryPostProcessor: замена bean-компонента DataSource DataSource на встроенную версию

2019-04-26 13:13:34.199 INFO 28627 --- [ main] osbfsDefaultListableBeanFactory: переопределение определения bean-компонента для bean 'dataSource'

2019-04-26 13: 13: 36.194 INFO 28627 --- [main] osjdeEmbeddedDatabaseFactory: запуск встроенной базы данных: url='jdbc:h2:mem:2784768e-f053-4bb3-ab88-edda34956893;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EX false', username='sa'

Примечание: у меня все еще есть свойства 'spring-jpa', определенные в 'application.properties', и я не использую никаких профилей. @ AutoConfigureTestDatabase переопределит существующие конфигурации jpa тестовыми значениями по умолчанию AutoConfigureTestDatabase.Replace.

Самое простое решение:

1) в src/main/resources есть application.properties (производственный конфиг):

spring.datasource.url=jdbc:mysql://localhost:3306/somedb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect

и application-test.properties с настройкой HSQL, например:

spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.database = HSQL
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HSQLDialect
spring.datasource.driverClassName = org.hsqldb.jdbcDriver
spring.datasource.url= jdbc:hsqldb:mem:scratchdb
spring.datasource.username = sa
spring.datasource.password =

2) Добавьте зависимость HSQL в pom.xml, если у вас ее еще нет.

3) Аннотируйте свой тестовый класс с помощью @ActiveProfiles("test").

Работал как шарм в моем случае.

У @Sanjay есть один способ выразить это, но я нахожу это запутанным. Вы могли бы также иметь только production профиль, который вы включаете, когда вы находитесь в производстве, что-то вроде:

spring.jpa.hibernate.ddl-auto: update
spring.datasource.url: jdbc:mysql://localhost:3306/dbname
spring.datasource.username: username
spring.datasource.password: password

И не указывайте ничего другого. Если вы добавите встроенную базу данных в test объем, он будет доступен в ваших тестах. Если вы запустите свои тесты с профилем по умолчанию (без каких-либо настроек), он не найдет никакой информации базы данных (так как она хранится в production профиль). В этом случае он попытается найти встроенную базу данных и запустить ее для вас. Если вам нужно больше настроек по какой-либо причине, вы можете иметь application-test.properties для тех (вам нужно добавить ActiveProfiles("test") к вашему тесту (ам).

Простое решение, если строить с maven: просто поместите application.properties файл под src/test/resources и отредактируйте при необходимости для тестирования.

Механизм Spring (Boot) Profile является довольно мощным инструментом, который по своему объему выходит далеко за рамки "переключения настроек между временем тестирования и временем выполнения". Хотя, как видно, это тоже можно сделать:)

Это решение позволяет использовать общие настройки для разработки и тестирования. Основано на этом решении: переопределить настройки Spring-Boot application.properties по умолчанию в тесте Junit

  1. application.properties в src / main / resources / application.properties
    #common settings for DEVELOPMENT and TEST:
    ......
    ......

    ## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
    spring.datasource.url=jdbc:postgresql://localhost:5432/databasename
    spring.datasource.username=postgres
    spring.datasource.password=somepassword

    # The SQL dialect makes Hibernate generate better SQL for the chosen database
    spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
    spring.jpa.properties.hibernate.jdbc.time_zone=UTC

    # Hibernate ddl auto (create, create-drop, validate, update)
    spring.jpa.hibernate.ddl-auto = none
    spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
  1. test.properties (src / main / resources / application.properties), который переопределяет и добавляет свойства в application.properties:
    spring.datasource.url=jdbc:h2:mem:testdb;MODE=PostgreSQL
    spring.datasource.driverClassName=org.h2.Driver
    spring.datasource.username=sa
    spring.datasource.password=
    spring.jpa.hibernate.ddl-auto=update
    spring.h2.console.enabled=false

  1. настройки в pom.xml для баз данных H2 и Postgre
      <!-- h2 -->
      <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
      </dependency>

    <!-- postgress -->
      <dependency>
         <groupId>org.postgresql</groupId>
         <artifactId>postgresql</artifactId>
      </dependency>

  1. В тестовом классе:
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @TestPropertySource(locations = "classpath:test.properties")
    public class ModelTest { 

    }

У меня есть многомодульный Gradle SpringBootApplication с модулями ниже

  1. employeemanagerApp - Где мой главный класс SpringApplication
  2. employeemanagerIntTests - Где у меня тесты на огурцы

Мое требование состояло в том, чтобы использовать MySQL DB при загрузке приложения и H2 во время моего тестирования интеграции с огурцом.

Решение: в моем модуле employeemanagerApp src / main / resources я разместил application.properties с приведенным ниже содержимым.

      #My SQL Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employeemanager
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update  spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

И в модуле тестирования интеграции (employeemanagerIntTests) src / test / resources я разместил application.properties с приведенным ниже содержимым

      #H2 In-Memory DB Configuration
spring.datasource.url=jdbc:h2://mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.format_sql=true

И в моем классе определения шага я добавил только эти аннотации

      @CucumberContextConfiguration
@SpringBootTest(classes = SpringBootApplicationMainClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

В файле build.gradle я добавил зависимость H2

      testImplementation 'com.h2database:h2:1.4.200'

Поэтому, когда я запускал свои тесты, H2 был активен, и все тесты с Create, Update, Read и Delete были успешными.

Другие вопросы по тегам