Как создать встроенную базу данных H2 во время модульного тестирования Mockito? - PullRequest
0 голосов
/ 24 мая 2019

В настоящее время я работаю над API Springboot, где было решено, что я и мои коллеги будем использовать встроенную базу данных H2 во время разработки.

База данных генерирует себя нормально при запуске приложения, но я не могу заставить ее работать во время модульного теста: все они не могут сказать org.h2.jdbc.JdbcSQLException: Table '[...]' not found.

Я практически не писал большую часть этого кода, пожалуйста, дайте мне знать, если вам нужно больше:

application.properties файл, в котором инициализируется база данных H2:

datasources.member-request.url=jdbc:h2:mem:db;IGNORECASE=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS DMDEOWNER\\;SET SCHEMA DMDEOWNER\\;runscript from 'classpath:h2_init_script.sql'
datasources.member-request.username=sa
datasources.member-request.password=
datasources.member-request.driver-class-name=org.h2.Driver
datasources.member-request.initialize=true

Как вы можете видеть выше, мы выполняем сценарий SQL при инициализации H2 под названием h2_init_script.sql, в этом файле у нас есть некоторый SQL-оператор, подобный этому (я покажу вам таблицу T_THEME, например)

/* CREATE statements */
CREATE TABLE DMDEOWNER.T_THEME (
    F_NUM_THEME NUMBER(14) NOT NULL,
    F_REF_THEME VARCHAR2(30) NOT NULL,
    F_LIB_THEME VARCHAR2(50) NOT NULL,
    F_POS_THEME NUMBER(4) NOT NULL,
    F_BOOL_ACTIF NUMBER(1) NOT NULL,
    F_UTILISATEUR_MAJ VARCHAR2(40) NOT NULL,
    F_DT_CREATION DATE NOT NULL,
    F_DT_MAJ DATE,
    PRIMARY KEY (F_NUM_THEME)
);

/* INSERT statements */
/* ... */

Вот мой тестовый класс (и его родитель):

public class ThemeRepositoryTest extends AbstractRepositoryTest {

  private final static int NB_ACTIVE_ENTITIES = 2;
  private final static int NB_INACTIVE_ENTITIES = 1;

  @Autowired
  private ThemeRepository repository;

  @Autowired
  private ThemeMapper mapper;


  // -------------------------------------------------------------------------
  // CREATE
  // -------------------------------------------------------------------------
  @Before
  public void init() {
    for (int i = INTEGER_ZERO; i < NB_ACTIVE_ENTITIES; i++) {
      insertTheme(true);
    }
    for (int i = INTEGER_ZERO; i < NB_INACTIVE_ENTITIES; i++) {
      insertTheme(false);
    }
    entityManager.flush();
  }

  // -------------------------------------------------------------------------
  // READ
  // -------------------------------------------------------------------------
  @Test
  public void findAll() {
    List<ThemeEntity> list = repository.findAll();
    assertEquals(NB_ACTIVE_ENTITIES + NB_INACTIVE_ENTITIES, list.size());
  }
}

@RunWith(SpringRunner.class)
@DataJpaTest
public abstract class AbstractRepositoryTest {

  @Autowired
  protected TestEntityManager entityManager;

  protected ThemeEntity insertTheme(boolean active) {
    ThemeEntity entity =  newThemeEntity(3L, "NAME", active, "USER");
    return entityManager.merge(entity);
  }
}

Вот где происходит моя ошибка в функции init(), когда я вызываю insertTheme():

findAll(io.lacipav.repository.ThemeRepositoryTest)  Time elapsed: 0.227 s  <<< ERROR!
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement
    at io.lacipav.repository.ThemeRepositoryTest.init(ThemeRepositoryTest.java:38)
Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement
    at io.lacipav.repository.ThemeRepositoryTest.init(ThemeRepositoryTest.java:38)
Caused by: org.h2.jdbc.JdbcSQLException: 
Table "T_THEME" not found; SQL statement:
select themeentit0_.f_num_theme as f_num_th1_11_0_, themeentit0_.f_bool_actif as f_bool_a2_11_0_, themeentit0_.f_dt_creation as f_dt_cre3_11_0_, themeentit0_.f_dt_maj as f_dt_maj4_11_0_, themeentit0_.f_lib_theme as f_lib_th5_11_0_, themeentit0_.f_pos_theme as f_pos_th6_11_0_, themeentit0_.f_ref_theme as f_ref_th7_11_0_, themeentit0_.f_utilisateur_maj as f_utilis8_11_0_ from t_theme themeentit0_ where themeentit0_.f_num_theme=? [42102-197]
    at io.lacipav.repository.ThemeRepositoryTest.init(ThemeRepositoryTest.java:38)

Так как ошибка говорит мне, что она не нашла мою таблицу, я предполагаю, что это потому, что моя база данных не работает, когда я создаю свой файл .war, если так, как я могу инициализировать его быстрее?

РЕДАКТИРОВАТЬ: Как и просили, вот класс Entity для T_THEME:

@Entity
@Getter
@Setter
@Table(name = "T_THEME")
public class ThemeEntity {

  /** Primary key of the table. */
  @Id
  @NotNull
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "theme_generator")
  @SequenceGenerator(name = "theme_generator", sequenceName = "SEQ_NUM_THEME", allocationSize = 1)
  @Column(name = "f_num_theme")
  private Long idTechnique;

  /** Theme functional identifier */
  @NotNull
  @Column(name = "f_ref_theme")
  private String reference;

  /** Theme simple short length label */
  @NotNull
  @Column(name = "f_lib_theme")
  private String name;

  //...
}

ПРИМЕЧАНИЕ. Последовательность SQL "SEQ_NUM_THEME" создается и связывается с F_NUM_THEME в сценарии SQL.

РЕДАКТИРОВАТЬ 2:

Как указал Lesiak, моя ошибка может быть связана с заменой моего источника данных аннотацией @DataJpaTest. Внимательно просмотрев логи, я нашел несколько интересных строк.

[INFO ] 2019-05-24 16:22:20.341 [main] org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceBeanFactoryPostProcessor.process(TestDatabaseAutoConfiguration.java:106) : Replacing 'dataSource' DataSource bean with embedded version
[INFO ] 2019-05-24 16:22:20.346 [main] org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:824) : Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]] with [Root bean: class [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
[INFO ] 2019-05-24 16:22:21.050 [main] org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.initDatabase(EmbeddedDatabaseFactory.java:189) : Starting embedded database: url='jdbc:h2:mem:4ef27020-c472-4be9-a9af-73f5e0175846;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'

В последней строке мы видим, что мое URL-соединение jdbc:h2:mem:db было заменено на jdbc:h2:mem:4ef27020-c472-4be9-a9af-73f5e0175846. Возможно, поэтому я получаю Table not found ошибок.

Ответы [ 2 ]

1 голос
/ 24 мая 2019

Проблема заключается в @DataJpaTest, который вы используете.См. Документация @DataJpaTest

. По умолчанию тесты, аннотированные @DataJpaTest, будут использовать встроенную базу данных в памяти (заменяя любой явный или обычно автоматически настраиваемый источник данных).Аннотация @AutoConfigureTestDatabase может использоваться для переопределения этих настроек.

В журнале вы найдете что-то похожее

EmbeddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version

Чтобы исправить, используйте:

spring.test.database.replace=none
spring.jpa.properties.hibernate.default_schema=DMDEOWNER 
0 голосов
/ 27 мая 2019

Я закончил тем, что пробовал так много вещей, что я не совсем уверен, почему это работает сейчас ...

В документации говорится, что по умолчанию он попытается найти schema.sql для создания базы данных и data.sql для ее заполнения. Я использовал свой собственный файл .sql, который выполнял обе задачи, поэтому я разделил его в соответствии с рекомендациями, и он начал работать!

Итак, теперь мой application.properties выглядит следующим образом:

# Datasource connection settings to H2 in-memory database
# To init db with h2_init_script.sql add the following to the url : INIT=CREATE SCHEMA IF NOT EXISTS DMDEOWNER\\;SET SCHEMA DMDEOWNER\\;runscript from 'classpath:h2_init_script.sql'
datasources.member-request.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;
datasources.member-request.username=sa
datasources.member-request.password=
datasources.member-request.driver-class-name=org.h2.Driver
datasources.member-request.initialize=true

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.web-allow-others=true

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

Поскольку я больше не создаю схему в application.properties, я добавил ее в файл schema.sql:

CREATE SCHEMA IF NOT EXISTS DMDEOWNER;
SET SCHEMA DMDEOWNER;

Наконец, я добавил префикс имени схемы в объявление последовательности в классах Entity, потому что у меня было несколько ошибок SEQUENCE NOT FOUND:

@Entity
@Getter
@Setter
@Table(name = "T_THEME")
public class ThemeEntity {

  /** Primary key of the table. */
  @Id
  @NotNull
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "theme_generator")
  @SequenceGenerator(name = "theme_generator", sequenceName = "DMDEOWNER.SEQ_NUM_THEME", allocationSize = 1)
  @Column(name = "f_num_theme")
  private Long idTechnique;

  //...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...