如何配置JPA以在Maven中进行测试

Pet*_*ker 67 java testing integration-testing maven-2 jpa

有没有办法在Maven项目中设置第二个persistence.xml文件,以便用于测试而不是用于部署的普通文件?

我尝试将一个persistence.xml放入src/test/resources/META-INF,它被复制到target/test-classes/META-INF中,但似乎是target/classes/META-INF(来自src/main的副本)尽管mvn -X test以正确的顺序列出了类路径条目,但首选资源是首选的:

[DEBUG] Test Classpath :
[DEBUG]   /home/uqpbecke/dev/NetBeansProjects/UserManager/target/test-classes
[DEBUG]   /home/uqpbecke/dev/NetBeansProjects/UserManager/target/classes
[DEBUG]   /home/uqpbecke/.m2/repository/junit/junit/4.5/junit-4.5.jar
...
Run Code Online (Sandbox Code Playgroud)

我希望能够针对简单的hsqldb配置运行测试,而无需更改JPA配置的部署版本,理想情况是在项目结账后直接进行,无需进行本地调整.

Ric*_*ler 26

以下内容适用于Maven 2.1+(在此之前,测试和包之间没有可以绑定执行的阶段).

您可以使用maven-antrun-plugin在测试期间将persistence.xml替换为测试版本,然后在打包项目之前恢复正确的版本.

此示例假定生产版本为src/main/resources/META-INF/persistence.xml,测试版本为src/test/resources/META-INF/persistence.xml,因此它们将被复制到target/classes/META -INF和target/test-classes/META-INF分别.

将它封装成mojo会更优雅,但是因为你只是复制一个文件,所以看起来有点过分.

<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.3</version>
  <executions>
    <execution>
      <id>copy-test-persistence</id>
      <phase>process-test-resources</phase>
      <configuration>
        <tasks>
          <!--backup the "proper" persistence.xml-->
          <copy file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
          <!--replace the "proper" persistence.xml with the "test" version-->
          <copy file="${project.build.testOutputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
    <execution>
      <id>restore-persistence</id>
      <phase>prepare-package</phase>
      <configuration>
        <tasks>
          <!--restore the "proper" persistence.xml-->
          <copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这是一个很好的解决方案.但是,可能还需要将overwite ="true"属性添加到最后一个Ant任务,以确保复制正确的XML文件.在我的环境中,由于目标和目标的时间戳相同,它似乎失败了. (2认同)

Arj*_*jan 21

在EE6/CDI/JPA项目中,src/test/resources/META-INF/persistence.xml无需进一步配置即可完成测试.

在Spring中使用JPA时,以下工作在用于测试的应用程序上下文中:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--
        JPA requires META-INF/persistence.xml, but somehow prefers the one
        in classes/META-INF over the one in test-classes/META-INF. Spring
        to the rescue, as it allows for setting things differently, like by
        referring to "classpath:persistence-TEST.xml". Or, simply referring
        to "META-INF/persistence.xml" makes JPA use the test version too: 
    -->
    <property name="persistenceXmlLocation" value="META-INF/persistence.xml" />

    <!-- As defined in /src/test/resources/META-INF/persistence.xml -->
    <property name="persistenceUnitName" value="myTestPersistenceUnit" />
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        </bean>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

在这里,/src/test/resources/META-INF/persistence.xml(复制到target/test-classes)将优先于/src/main/resources/META-INF/persistence.xml(复制到target/classes).

Unfortunately, the location of the persistence.xml file also determines the so-called "persistence unit's root", which then determines which classes are scanned for @Entity annotations. So, using /src/test/resources/META-INF/persistence.xml would scan classes in target/test-classes, not classes in target/classes (where the classes that need to be tested would live).

Hence, for testing, one would need to explicitly add <class> entries to persistence.xml, to avoid java.lang.IllegalArgumentException: Not an entity: class .... The need for <class> entries can be avoided by using a different file name, like persistence-TEST.xml, and put that file in the very same folder as the regular persistence.xml file. The Spring context from your test folder can then just refer to <property name="persistenceXmlLocation" value="META-INF/persistence-TEST.xml" />, and Spring will find it for you in src/main.

作为替代方案,可以persistence.xml为实际应用程序和测试保持相同,并且仅定义一个src/main.大多数配置(如驱动程序,方言和可选凭据)都可以在Spring上下文中完成.还hibernate.hbm2ddl.auto可以在上下文中传递设置:

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!-- For example: com.mysql.jdbc.Driver or org.h2.Driver -->
    <property name="driverClassName" value="#{myConfig['db.driver']}" />
    <!-- For example: jdbc:mysql://localhost:3306/myDbName or 
        jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 -->
    <property name="url" value="#{myConfig['db.url']}" />
    <!-- Ignored for H2 -->
    <property name="username" value="#{myConfig['db.username']}" />
    <property name="password" value="#{myConfig['db.password']}" />
</bean>

<bean id="jpaAdaptor"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <!-- For example: org.hibernate.dialect.MySQL5Dialect or 
        org.hibernate.dialect.H2Dialect -->
    <property name="databasePlatform" value="#{myConfig['db.dialect']}" />
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="jpaProperties">
        <props>
            <!-- For example: validate, update, create or create-drop -->
            <prop key="hibernate.hbm2ddl.auto">#{myConfig['db.ddl']}</prop>
            <prop key="hibernate.show_sql">#{myConfig['db.showSql']}</prop>
            <prop key="hibernate.format_sql">true</prop>
        </props>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

  • 原始问题中没有关于弹簧的字样。 (2认同)

Pet*_*ker 13

似乎多个persistence.xml文件是JPA的一般问题,只能通过类加载技巧来解决.

对我有用的解决方法是在一个persistence.xml文件中定义多个持久性单元,然后确保您的部署和测试代码使用不同的绑定(在Spring中,您可以在实体管理器工厂中设置"persistenceUnitName"属性).它会使用测试配置污染您的部署文件,但如果您不介意它可以正常工作.


Vla*_*-HC 9

为测试添加一个persistance.xml:/src/test/resources/META-INF/persistence.xml 正如@Arjan所说,这将改变持久性单元的根,实体类将在目标/测试类中进行扫描.要处理它,请将jar-file元素添加到此persistance.xml:

/src/test/resources/META-INF/persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="com.some.project">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jar-file>${project.basedir}/target/classes</jar-file>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/test_database" />
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.user" value="user" />
            <property name="javax.persistence.jdbc.password" value="..." />
        </properties>
    </persistence-unit>
</persistence>
Run Code Online (Sandbox Code Playgroud)

然后,将测试资源的过滤添加到pom.xml:

<project>
    ...
    <build>
        ...
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>
        </testResources>
        ...
    </build>
...
</project>
Run Code Online (Sandbox Code Playgroud)

这将起作用,因为jar文件可以定位到目录,而不仅仅是jar文件.


小智 6

我尝试了ClassLoaderProxy方法但遇到的问题是,JPA带注释的类不会被hibernate作为持久化类处理.

所以决定不使用persistence.xml就试一试.优点是maven构建和Eclipse JUnit测试无需修改即可运行.

我有一个用于JUnit测试的persitent支持类.

public class PersistenceTestSupport {

    protected EntityManager em;
    protected EntityTransaction et;

    /**
     * Setup the the {@code EntityManager} and {@code EntityTransaction} for
     * local junit testing.
     */
    public void setup() {

        Properties props = new Properties();
        props.put("hibernate.hbm2ddl.auto", "create-drop");
        props.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        props.put("hibernate.connection.url", "jdbc:mysql://localhost/db_name");
        props.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
        props.put("hibernate.connection.username", "user");
        props.put("hibernate.connection.password", "****");

        Ejb3Configuration cfg = new Ejb3Configuration();
        em = cfg.addProperties(props)
            .addAnnotatedClass(Class1.class)
            .addAnnotatedClass(Class2.class)
            ...
                    .addAnnotatedClass(Classn.class)
            .buildEntityManagerFactory()
            .createEntityManager();

        et = em.getTransaction();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试类只是扩展PersistenceTestSupport并调用TestCase.setup()中的setup().

唯一的缺点是保持持久化的类,但对于JUnit测试,这对我来说是可以接受的.


小智 5

我更喜欢使用不同的persistence.xml作为Rich Seller 帖子进行测试和制作的解决方案(谢谢!!).

但需要改变:

<copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
Run Code Online (Sandbox Code Playgroud)

对于:

<move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
Run Code Online (Sandbox Code Playgroud)

为了使persistence.xml.proper不嵌入.jar文件中


TRF*_*TRF 3

保留 persistence.xml 文件的两个副本。一个用于测试,另一个用于正常构建。

默认生命周期将构建的 persistence.xml 复制到 src/test/resources/META-INF

创建一个单独的配置文件,运行时会将测试 persistence.xml 复制到 src/test/resources/META-INF