Использование отдельных файлов persistence.xml для производства и тестирования в Spring 3.1 - PullRequest
6 голосов
/ 29 марта 2012

ОК, извините, я искал ответы на эти вопросы часами, но мне потребовалось ввести весь вопрос для StackOverflow, чтобы всплыть нужная ссылка. Вы можете прочитать много соответствующей информации здесь .


У меня есть проект Spring, созданный с помощью Spring Roo для использования Hibernate и MySQL. Однако для тестирования я хочу использовать HSQLDB в памяти, потому что тесты интеграции Roo удаляют данные с идентификаторами (первичными ключами) от 0 до 10 (вместо того, чтобы удалять данные с помощью назначенных для базы данных идентификаторов для данных, которые они уже создали), что означает, что это удаляет данные, которые уже находятся в базе данных, что в моем случае приводит к нарушению ограничения, прежде чем происходит откат транзакции.

Это немного сложнее, потому что я переключаю целые провайдеры баз данных, что означает разные диалекты Hibernate, а также разные настройки DDL (проверка в процессе производства, проверка на создание-падение). Но это не работает так, как я ожидал, и я озадачен, почему.

Если вы знаете, почему это не работает, скажите, пожалуйста, даже если у вас нет решения.

Это проект Roo, я, конечно, использую Maven. Итак, первое, что я попробовал, было наличие файла src/test/resources/META-INF/persistence.xml для конкретного теста, а также файла src/test/resources/META-INF/spring/database.properties для конкретного теста. Это не сработало, как когда я запустил mvn test все сломалось, с соответствующим сообщением было

Conflicting persistence unit definitions for name 'persistenceUnit'

Почему mvn test все еще собирает не тестовые ресурсы?

Итак, я переименовал src/test/resources/META-INF/spring в spring-test и скопировал applicationContext.xml в него. Я изменил конфигурацию контекста в тестовых классах на

@ContextConfiguration(locations = "classpath:/META-INF/spring-test/applicationContext*.xml")

Завершая (или я так думал) разделение, я сделал пару правок для spring-test/applicationContext.xml:

Изменен путь к файлам свойств:

<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>

до

<context:property-placeholder location="classpath*:META-INF/spring-test/*.properties"/>

Изменено название персистентного юнита:

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

до

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="testPersistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

И я сделал соответствующее изменение имени единицы персистентности на src/test/resources/META-INF/persistence.xml

Хорошо, хорошо, теперь нет никакого конфликта, но каким-то образом Hibernate потерял сопоставления сущностей (например, для сущности Product), и я получаю:

org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.hql.ast.QuerySyntaxException: Product is not mapped [SELECT o FROM Product o]; 

Почему Spring / Hibernate потерял сопоставления сущностей в этой конфигурации?

Итак, следующее, что я попробовал, - это объединение двух файлов persistence.xml, чтобы один файл в src/main/resources/META-INF включал в себя оба постоянных элемента.

Это работает !! ??

Я думаю, что это ужасно, потому что теперь у меня есть тестовая конфигурация в моем производственном коде, но это то, с чем я справляюсь.

Какой способ лучше?

Насколько я понимаю, свойства не доступны в файле persistence.xml, как в файлах Spring XML. Поэтому я не думаю, что смогу делать то, что хочу, только с помощью файла свойств для конкретного теста.

В идеале я бы запускал тесты, используя всю конфигурацию в src / main / resources, за исключением того, что специально переопределено в src / test / resources. Есть ли способ сделать это?

Спасибо за любую информацию, которую вы можете предоставить!

1 Ответ

1 голос
/ 29 марта 2012

В своей работе я настраивал файл persistence.xml без информации о подключении к базе данных. Соединение с базой данных определяется конфигурацией контекста Spring. В платформе Spring есть несколько способов изменить свойства объекта:

  1. PropertyPlaceholderConfigurer - Использование другого файла свойств для переопределения значения соединения с базой данных или диалекта ORM. Вы можете использовать фильтр ресурсов для генерации различных значений одного файла свойств, если вы используете Maven
  2. Наследование определения компонента - Использование другой конфигурации контекста для "переопределения" конфигурации по умолчанию.

Следующий код является выдержкой из моего контекста приложения:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    p:location="classpath:frontend.properties" p:ignore-resource-not-found="true"
    p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE"
/>

<util:properties id="jpaProperties">
    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
</util:properties>

<!-- Global entity manager factory(may not be overrided) -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaProperties-ref="jpaProperties"
>
    <property name="JpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>
<!-- :~) -->

<!-- Data Source -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"
    p:driverClass="${database.driverClass}" p:jdbcUrl="${database.url}"
    p:username="${database.username}" p:password="${database.password}"
    p:partitionCount="${database_conn.pooling.partition_count:2}"
    p:maxConnectionsPerPartition="64" p:minConnectionsPerPartition="${database_conn.pooling.min_connections:4}"
    p:acquireIncrement="4" p:statementsCacheSize="64"
    p:connectionTimeoutInMs="1800000" p:IdleConnectionTestPeriodInMinutes="420"
/>
<!-- :~) -->

Вот конфигурация для тестирования:

<!-- import configuration of application -->
<import resource="classpath:database.xml" />

<!--
  - I override some of settings of connection pooling while testing
  -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"
    p:driverClass="${database.driverClass}" p:jdbcUrl="${database.url}"
    p:username="${database.username}" p:password="${database.password}"
    p:maxConnectionsPerPartition="8" p:minConnectionsPerPartition="2"
    p:acquireIncrement="2" p:statementsCacheSize="32"
/>

Когда я запускаю тест, я настраиваю системные свойства в Maven surefire для настройки другой базы данных. Как следующий образец:

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-surefire-plugin</artifactId>
     <version>2.8.1</version>
     <configuration>
         <systemPropertyVariables>
             <!-- Using HSQLDB as test database system -->
             <database.driverClass>org.hsqldb.jdbc.JDBCDriver</database.driverClass>
             <database.url>${database.hsqldb.url}</database.url>
             <database.username>any</database.username>
             <database.password>any</database.password
             <hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect>
             <!-- :~) -->
         </systemPropertyVariables>
     </configuration>
</plugin>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...