如何为Maven中的测试配置JPA ?

时间:2022-01-29 12:02:03

Is there a way to set up a second persistence.xml file in a Maven project such that it is used for testing instead of the normal one that is used for deployment?

有办法建立第二个持久性吗?Maven项目中的xml文件,以便用于测试而不是用于部署的常规文件?

I tried putting a persistence.xml into src/test/resources/META-INF, which gets copied into target/test-classes/META-INF, but it seems target/classes/META-INF (the copy from the src/main/resources) gets preferred, despite mvn -X test listing the classpath entries in the right order:

我试着坚持。将xml转换为src/test/resources/META-INF,将其复制到目标/测试类/META-INF中,但是似乎目标/类/META-INF(来自src/主/资源的拷贝)是首选的,尽管mvn -X测试列出了正确顺序的类路径条目:

[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
...

I would like to be able to run tests against a simple hsqldb configuration without having to change the deployment version of the JPA configuration, ideally straight after project checkout without any need for local tweaking.

我希望能够对简单的hsqldb配置进行测试,而无需更改JPA配置的部署版本,最好是在项目签出后直接进行,而不需要进行局部调整。

16 个解决方案

#1


26  

The following will work for Maven 2.1+ (prior to that there wasn't a phase between test and package that you could bind an execution to).

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

You can use the maven-antrun-plugin to replace the persistence.xml with the test version for the duration of the tests, then restore the proper version before the project is packaged.

您可以使用maven-antrun插件来替换持久性。在测试期间使用测试版本的xml,然后在打包项目之前恢复适当的版本。

This example assumes the production version is src/main/resources/META-INF/persistence.xml and the test version is src/test/resources/META-INF/persistence.xml, so they will be copied to target/classes/META-INF and target/test-classes/META-INF respectively.

这个例子假设生产版本是src/main/resources/META-INF/persistence。xml和测试版本是src/test/resources/META-INF/持久性。将它们分别复制到目标/类/META-INF和目标/测试类/META-INF。

It would be more elegant to encapsulate this into a mojo, but as you're only copying a file, it seems like overkill.

将它封装到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>

#2


20  

In an EE6/CDI/JPA project, a test src/test/resources/META-INF/persistence.xml is picked up just fine without any further configuration.

在EE6/CDI/JPA项目中,测试src/test/resources/META-INF/持久性。在没有任何进一步配置的情况下,xml被恢复得很好。

When using JPA in Spring, the following works in the application context used for testing:

在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>

Here, /src/test/resources/META-INF/persistence.xml (copied into target/test-classes) would be preferred over /src/main/resources/META-INF/persistence.xml (copied into target/classes).

在这里,/ src /测试/资源/ meta - inf /持久性。xml(复制到目标/测试类)比/src/main/resources/META-INF/持久性更可取。xml(复制到目标/ 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).

不幸的是,持久性的位置。xml文件还确定所谓的“持久性单元的根”,然后它确定要扫描哪些类以获取@Entity注释。所以,使用/ src /测试/资源/ meta - inf /持久性。xml将扫描目标/测试类中的类,而不是目标/类中的类(需要测试的类将存在)。

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.

因此,对于测试,需要显式地向持久性添加 条目。xml,以避免. lang。IllegalArgumentException:不是一个实体:类....可以通过使用不同的文件名(如持久化测试)来避免使用 条目。将该文件放入与常规持久性相同的文件夹中。xml文件。然后,测试文件夹中的Spring上下文就可以引用 , Spring会在src/main中为您找到它。

As an alternative, one might be able to keep persistence.xml the same for the actual application and the tests, and only define one in src/main. Most configuration such as the drivers, dialect and optional credentials can be done in the Spring context instead. Also settings such as hibernate.hbm2ddl.auto can be passed in the context:

作为另一种选择,一个人可以保持坚持。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>

#3


13  

It seems multiple persistence.xml files is a general problem with JPA, solved only by classloading tricks.

似乎多个持久性。xml文件是JPA的一个普遍问题,只能通过类加载技巧来解决。

A workaround that works for me is to define multiple persistence units in one persistence.xml file and then make sure that your deployment and test code use a different binding (in Spring you can set the "persistenceUnitName" property on the entity manager factory). It pollutes your deployment file with the test configuration, but if you don't mind that it works ok.

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

#4


6  

I tried the ClassLoaderProxy approach but had the problem that the JPA annotated classes are not handled as persistent classes by hibernate.

我尝试了ClassLoaderProxy方法,但是有一个问题,JPA注释的类没有被hibernate作为持久化类来处理。

So decided to try it without using persistence.xml. The advantage is that the maven build and the Eclipse JUnit test will work without modifications.

因此决定不使用persistence.xml进行尝试。优点是,maven构建和Eclipse JUnit测试将在不需要修改的情况下进行工作。

I have a persitent support class for JUnit testing.

我有一个用于JUnit测试的持久化支持类。

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();
    }
}

My test classes just extend PersistenceTestSupport and call the setup() in TestCase.setup().

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

The only drawback is to keep the persistent classes up todate, but for JUnit testing this is acceptable for me.

惟一的缺点是使持久化类保持最新,但是对于JUnit测试,这对我来说是可以接受的。

#5


6  

Add a persistance.xml for tests: /src/test/resources/META-INF/persistence.xml As @Arjan said, that would change persistance unit's root and entity classes would be scanned in target/test-classes. To handle that, add jar-file element to this persistance.xml:

添加一个持久性。xml测试:/ src /测试/资源/ meta - inf /持久性。正如@Arjan所说的,这将改变持久化单元的根类和实体类将在目标/测试类中被扫描。要处理这个问题,请向这个persistence .xml添加jar-file元素:

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

/ src /测试/资源/ 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>

Then, add filtering of test resources to your pom.xml:

然后,在您的pom.xml中添加测试资源的过滤:

<project>
    ...
    <build>
        ...
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>
        </testResources>
        ...
    </build>
...
</project>

This will work because jar-file can target to directories, not only to jar files.

这将起作用,因为jar文件可以针对目录,而不仅仅是jar文件。

#6


5  

I prefer the solution of using different persistence.xml for testing and production as Rich Seller post (thanks!!).

我更喜欢使用不同持久性的解决方案。用于测试和生产的xml作为富卖家post(谢谢!)

But need to change:

但是需要更改:

<copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>

for:

:

<move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>

In order persistence.xml.proper not embedded in .jar file

persistence . xml。正确的不嵌入。jar文件

#7


3  

Keep two copies of persistence.xml file. One for testing and another for normal build.

保留两份持久性。xml文件。一个用于测试,另一个用于正常构建。

The default life cycle copy the build persistence.xml to src/test/resources/META-INF

默认的生命周期复制构建持久性。xml到src / meta - inf /测试/资源

Create a separate profile which when run will copy the testing persistence.xml to src/test/resources/META-INF

创建一个单独的概要文件,运行时将复制测试持久性。xml到src / meta - inf /测试/资源

#8


3  

Persistence.xml is used as a starting point to search for entity classes unless you list all classes explicitly and add . So if you want to override this file with another one, say from src/test/resources, you have to specify every single entity class in this second persistence.xml otherwise no entity class would be found.

持久性。xml被用作搜索实体类的起点,除非您显式地列出所有类并添加。如果你想用另一个文件覆盖这个文件,比如从src/test/resources,你必须在第二个持久性中指定每个实体类。否则将不会找到任何实体类。

Another solution would be to overwrite the file using the maven-resources-plugin ('copy-resources' goal). But then you have to overwrite it twice, once for testing (e.g. phase process-test-classes) and once for the real packaging (phase 'prepare-package').

另一个解决方案是使用maven-resources-plugin(“copy-resources”目标)覆盖文件。但是您必须重写它两次,一次用于测试(例如阶段过程测试类),一次用于真正的打包(阶段“准备包”)。

#9


3  

This answer might sounds silly but I was looking for a way which lets me run those tests from eclipse by Run As -> JUnit Test. This is how I made it:

这个答案可能听起来很傻,但我正在寻找一种方法,可以让我以-> JUnit测试的形式从eclipse运行这些测试。我就是这样做的:

@BeforeClass
public static void setUp() throws IOException {
    Files.copy(new File("target/test-classes/META-INF/persistence.xml"), new File("target/classes/META-INF/persistence.xml"));
    // ...
}

I'm just copying the test/persistence.xml to classes/persistence.xml. This works.

我只是在复制测试/持久性。xml类/ persistence . xml。这个作品。

#10


1  

I'm trying to do the same thing. I have a solution that works for me - yours may vary (and you might not love the solution... it's a bit low-level).

我也在做同样的事情。我有一个适合我的解决方案——你的方案可能不同(你可能不喜欢这个方案……)这有点低级)。

I came across an article on the net where they were using a custom class loader to do something similar which served as inspiration. If anyone can see how to improve then suggestions would be welcome btw. For deployment I rely on container injection of the EntityManager but for testing I create it myself using this code:

我在网上看到一篇文章,他们使用自定义类装入器来做类似的事情,这可以作为灵感。如果有人能看到如何改进,那么建议将受到欢迎。对于部署,我依赖于EntityManager的容器注入,但是为了测试,我自己使用这个代码创建它:

final Thread currentThread = Thread.currentThread();
final ClassLoader saveClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(new ClassLoaderProxy(saveClassLoader));

EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("test");
em = emFactory.createEntityManager();

Then the ClassLoaderProxy is about as minimal as you can get and just redirects requests for META-INF/persistence.xml to META-INF/test-persist.xml:

然后ClassLoaderProxy就会尽可能地最小化,并且只需重定向对META-INF/持久性的请求。xml meta - inf / test-persist.xml:

public class ClassLoaderProxy extends ClassLoader {

    public ClassLoaderProxy(final ClassLoader parent) {
        super();
    }

    @Override
    public Enumeration<URL> getResources(final String name) throws IOException {
        if (!"META-INF/persistence.xml".equals(name)) {
            return super.getResources(name);
        } else {
            System.out.println("Redirecting persistence.xml to test-persist.xml");
            return super.getResources("META-INF/test-persist.xml");
        }
    }
}

Just to explain this a bit more:

再解释一下

  1. There are two persistence.xml files (one named persistence.xml that is used outside testing and one named test-persist.xml that is used for tests).
  2. 有两个持久性。xml文件(名为持久性)。用于外部测试和名为test-persist的xml。用于测试的xml)。
  3. The custom class loader is only active for unit tests (for deployment everything is normal)
  4. 自定义类装入器仅用于单元测试(对于部署来说,一切都是正常的)
  5. The custom class loader redirects requests for "META-INF/persistence.xml" to the test version ("META-INF/test-persist.xml").
  6. 自定义类装入器重定向“META-INF/持久性”请求。xml到测试版本(“META-INF/test- persistence .xml”)。

I was originally hitting some problems because Hibernate will revert back (somehow) to the classloader that was used to load Hibernate (at least I think that is what was going on). I've found that putting the ClassLoader switching code (the first block) as a static block in your Test case it will get loaded before Hibernate but that, depending on your unit test structure you may also need to put the same code in other places (yuck).

我最初遇到了一些问题,因为Hibernate会(以某种方式)恢复到用来装载Hibernate的类加载器(至少我认为是这样)。我发现将类加载器切换代码(第一个块)作为测试用例中的静态块将在Hibernate之前加载,但是根据单元测试结构,您可能还需要将相同的代码放在其他地方(呸)。

#11


1  

Another approach is to use a separate persistence.xml for testing (test/../META-INF/persistence.xml but override the Scanner as follows: -

另一种方法是使用单独的持久性。xml用于测试(测试/ . . / meta - inf /持久性。但覆盖扫描仪如下:-

testing persistence.xml needs to contain

测试的持久性。xml需要包含

<property name="hibernate.ejb.resource_scanner" value = "...TestScanner" />

<属性名= " hibernate.ejb。resource_scanner“价值="……TestScanner ">

Code for new class TestScanner is as follows.

新类TestScanner的代码如下所示。

import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import org.hibernate.ejb.packaging.NamedInputStream;
import org.hibernate.ejb.packaging.NativeScanner;


public class TestScanner extends NativeScanner
{

@Override
public Set <Class <?> > 
getClassesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getClassesInJar (getUpdatedURL (jar), annotations); }

@Override
public Set <NamedInputStream> 
getFilesInJar (URL jar, Set <String> patterns)
{  return super.getFilesInJar (getUpdatedURL (jar), patterns); }

@Override
public Set <Package> 
getPackagesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getPackagesInJar (getUpdatedURL (jar), annotations); }

private URL getUpdatedURL (URL url)
{
  String oldURL = url.toExternalForm ();
  String newURL = oldURL.replaceAll ("test-classes", "classes");
  URL result;
  try {
    result = newURL.equals (oldURL) ? url : new URL (newURL);
  } catch (MalformedURLException e)
  {  // Whatever  }
  return result;
}

}

#12


1  

Another option for this use case would be adding multiple persistence units, one for lets say production and another one for testing and inject the EntityManagerFactory accordingly.

这个用例的另一个选项是添加多个持久性单元,一个用于let say production,另一个用于测试和注入EntityManagerFactory。

Place both persistence-units into the persistence.xml of the actual project and have your test cases inject the correct EntityManager. The example below illustrates how to do that with guice. Please note that I've left in some mockito mocking for completeness, the mockito specific code has been marked accordingly and is not required for injection.

将两个持久化单元都放到持久性中。实际项目的xml,并让您的测试用例注入正确的EntityManager。下面的示例演示了如何使用guice实现这一点。请注意,我在一些mockito中留了一些mock作为完整性,mockito特定的代码已经被相应地标记,不需要注入。

public class HibernateTestDatabaseProvider extends AbstractModule {
    private static final ThreadLocal<EntityManager> ENTITYMANAGER_CACHE = new ThreadLocal<>();

    @Override
    public void configure() {
    }

    @Provides
    @Singleton
    public EntityManagerFactory provideEntityManagerFactory() {
        return Persistence.createEntityManagerFactory("my.test.persistence.unit");
    }

    @Provides
    public CriteriaBuilder provideCriteriaBuilder(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.getCriteriaBuilder();
    }

    @Provides
    public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {
        EntityManager entityManager = ENTITYMANAGER_CACHE.get();
        if (entityManager == null) {
            // prevent commits on the database, requires mockito. Not relevant for this answer
            entityManager = spy(entityManagerFactory.createEntityManager());


            EntityTransaction et = spy(entityManager.getTransaction());
            when(entityManager.getTransaction()).thenReturn(et);
            doNothing().when(et).commit();

            ENTITYMANAGER_CACHE.set(entityManager);
        }
        return entityManager;
    }
}

#13


0  

put tests in own maven project with its persistence.xml

将测试放在带有persistence.xml的maven项目中

#14


0  

When using OpenEJB, persistence.xml can be overriden with alternate descriptors: http://tomee.apache.org/alternate-descriptors.html

当使用OpenEJB、持久性。xml可以用替代描述符来覆盖:http://e.apache.org/e-descriptors.html。

#15


0  

I'd suggest using different maven profiles where you could filter your database.proprerties files and have one database.properties per profile.

我建议使用不同的maven配置文件来过滤数据库。proprerties文件和一个数据库。每个配置文件属性。

This way you don't have to keep duplicates of any other configuration files except for the .properties.

这样,除了.properties之外,您不必保留任何其他配置文件的副本。

<properties>
    <!-- Used to locate the profile specific configuration file. -->
    <build.profile.id>default</build.profile.id>
    <!-- Only unit tests are run by default. -->
    <skip.integration.tests>true</skip.integration.tests>
    <skip.unit.tests>false</skip.unit.tests>
    <integration.test.files>**/*IT.java</integration.test.files>
</properties>
<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>default</build.profile.id>
            <skip.integration.tests>true</skip.integration.tests>
            <skip.unit.tests>false</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file should be the default spring/database.properties file
                -->
                <filter>src/main/resources/META-INF/spring/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
    <profile>
        <id>integration</id>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>integration</build.profile.id>
            <skip.integration.tests>false</skip.integration.tests>
            <skip.unit.tests>true</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file is searched
                    from spring/profiles/it/ directory.
                -->
                <filter>src/main/resources/META-INF/spring/profiles/${build.profile.id}/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
</profiles>

With the help of surefire for unit tests and failsfe for integration tests, you're done.

在确保单元测试和集成测试失败的帮助下,您已经完成了。

    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <junitArtifactName>org.junit:com.springsource.org.junit</junitArtifactName>
        <!--see: https://issuetracker.springsource.com/browse/EBR-220-->
        <printSummary>false</printSummary>
        <redirectTestOutputToFile>true</redirectTestOutputToFile>
        <!-- Skips unit tests if the value of skip.unit.tests property is true -->
        <skipTests>${skip.unit.tests}</skipTests>
        <!-- Excludes integration tests when unit tests are run. -->
        <excludes>
            <exclude>${integration.test.files}</exclude>
        </excludes>
    </configuration>
</plugin>


<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <!-- Skips integration tests if the value of skip.integration.tests property is true -->
        <skipTests>${skip.integration.tests}</skipTests>
        <includes>
            <include>${integration.test.files}</include>
        </includes>
        <forkMode>once</forkMode>
        <!--
                            <reuseForks>false</reuseForks>
                            <forkCount>1</forkCount>
        -->
    </configuration>
    <executions>
        <execution>
            <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Now you need just mvn test for your unit tests and mvn verify -Pintegration for your integration tests. Obviously you should create the database.properties files in the specified (on the profiles) paths (or elsewhere and change the paths)

现在,您只需对单元测试进行mvn测试,并对集成测试进行mvn验证-Pintegration。显然,您应该创建数据库。指定(在概要文件上)路径中的属性文件(或其他地方并更改路径)

Based-on reference: http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

基于参考:http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

#16


0  

This is an extension of Rich Seller's answer with proper handling of Hibernate finding multiple persistence.xml files on the classpath and pre-testing state restoration.

这是富卖家的答案的扩展,正确地处理Hibernate,找到多重持久性。类路径上的xml文件和测试状态恢复。

Setup:

Create one persistence file for deployment/packaging and one for testing:

创建一个用于部署/打包的持久性文件和一个用于测试的持久性文件:

  • src/main/resources/persistence.xml

    src / main /资源/ persistence . xml

  • src/test/resources/persistence-testing.xml

    src /测试/资源/ persistence-testing.xml

in your pom.xml add this to the plugins section:

砰的一声。xml将其添加到插件部分:

        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
            <executions>
                <execution>
                    <id>copy-test-persistence</id>
                    <phase>process-test-resources</phase>
                    <configuration>
                        <tasks>
                            <echo>renaming deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
                            <echo>replacing deployment persistence.xml with test version</echo>
                            <copy file="${project.build.testOutputDirectory}/META-INF/persistence-testing.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>restore-persistence</id>
                    <phase>prepare-package</phase>
                    <configuration>
                        <tasks>
                            <echo>restoring the deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Advantages over other solutions

  • No extra Java code required
  • 不需要额外的Java代码
  • Only one persistence.xml on classpath
  • 只有一个持久性。xml在类路径中
  • Both building and testing work as expected
  • 构建和测试工作都和预期的一样。
  • Describing output on console (echo)
  • 描述控制台上的输出(echo)
  • For packaging the state is 100% restored. No leftover files
  • 包装状态100%恢复。没有剩下的文件

#1


26  

The following will work for Maven 2.1+ (prior to that there wasn't a phase between test and package that you could bind an execution to).

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

You can use the maven-antrun-plugin to replace the persistence.xml with the test version for the duration of the tests, then restore the proper version before the project is packaged.

您可以使用maven-antrun插件来替换持久性。在测试期间使用测试版本的xml,然后在打包项目之前恢复适当的版本。

This example assumes the production version is src/main/resources/META-INF/persistence.xml and the test version is src/test/resources/META-INF/persistence.xml, so they will be copied to target/classes/META-INF and target/test-classes/META-INF respectively.

这个例子假设生产版本是src/main/resources/META-INF/persistence。xml和测试版本是src/test/resources/META-INF/持久性。将它们分别复制到目标/类/META-INF和目标/测试类/META-INF。

It would be more elegant to encapsulate this into a mojo, but as you're only copying a file, it seems like overkill.

将它封装到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>

#2


20  

In an EE6/CDI/JPA project, a test src/test/resources/META-INF/persistence.xml is picked up just fine without any further configuration.

在EE6/CDI/JPA项目中,测试src/test/resources/META-INF/持久性。在没有任何进一步配置的情况下,xml被恢复得很好。

When using JPA in Spring, the following works in the application context used for testing:

在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>

Here, /src/test/resources/META-INF/persistence.xml (copied into target/test-classes) would be preferred over /src/main/resources/META-INF/persistence.xml (copied into target/classes).

在这里,/ src /测试/资源/ meta - inf /持久性。xml(复制到目标/测试类)比/src/main/resources/META-INF/持久性更可取。xml(复制到目标/ 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).

不幸的是,持久性的位置。xml文件还确定所谓的“持久性单元的根”,然后它确定要扫描哪些类以获取@Entity注释。所以,使用/ src /测试/资源/ meta - inf /持久性。xml将扫描目标/测试类中的类,而不是目标/类中的类(需要测试的类将存在)。

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.

因此,对于测试,需要显式地向持久性添加 条目。xml,以避免. lang。IllegalArgumentException:不是一个实体:类....可以通过使用不同的文件名(如持久化测试)来避免使用 条目。将该文件放入与常规持久性相同的文件夹中。xml文件。然后,测试文件夹中的Spring上下文就可以引用 , Spring会在src/main中为您找到它。

As an alternative, one might be able to keep persistence.xml the same for the actual application and the tests, and only define one in src/main. Most configuration such as the drivers, dialect and optional credentials can be done in the Spring context instead. Also settings such as hibernate.hbm2ddl.auto can be passed in the context:

作为另一种选择,一个人可以保持坚持。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>

#3


13  

It seems multiple persistence.xml files is a general problem with JPA, solved only by classloading tricks.

似乎多个持久性。xml文件是JPA的一个普遍问题,只能通过类加载技巧来解决。

A workaround that works for me is to define multiple persistence units in one persistence.xml file and then make sure that your deployment and test code use a different binding (in Spring you can set the "persistenceUnitName" property on the entity manager factory). It pollutes your deployment file with the test configuration, but if you don't mind that it works ok.

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

#4


6  

I tried the ClassLoaderProxy approach but had the problem that the JPA annotated classes are not handled as persistent classes by hibernate.

我尝试了ClassLoaderProxy方法,但是有一个问题,JPA注释的类没有被hibernate作为持久化类来处理。

So decided to try it without using persistence.xml. The advantage is that the maven build and the Eclipse JUnit test will work without modifications.

因此决定不使用persistence.xml进行尝试。优点是,maven构建和Eclipse JUnit测试将在不需要修改的情况下进行工作。

I have a persitent support class for JUnit testing.

我有一个用于JUnit测试的持久化支持类。

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();
    }
}

My test classes just extend PersistenceTestSupport and call the setup() in TestCase.setup().

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

The only drawback is to keep the persistent classes up todate, but for JUnit testing this is acceptable for me.

惟一的缺点是使持久化类保持最新,但是对于JUnit测试,这对我来说是可以接受的。

#5


6  

Add a persistance.xml for tests: /src/test/resources/META-INF/persistence.xml As @Arjan said, that would change persistance unit's root and entity classes would be scanned in target/test-classes. To handle that, add jar-file element to this persistance.xml:

添加一个持久性。xml测试:/ src /测试/资源/ meta - inf /持久性。正如@Arjan所说的,这将改变持久化单元的根类和实体类将在目标/测试类中被扫描。要处理这个问题,请向这个persistence .xml添加jar-file元素:

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

/ src /测试/资源/ 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>

Then, add filtering of test resources to your pom.xml:

然后,在您的pom.xml中添加测试资源的过滤:

<project>
    ...
    <build>
        ...
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>
        </testResources>
        ...
    </build>
...
</project>

This will work because jar-file can target to directories, not only to jar files.

这将起作用,因为jar文件可以针对目录,而不仅仅是jar文件。

#6


5  

I prefer the solution of using different persistence.xml for testing and production as Rich Seller post (thanks!!).

我更喜欢使用不同持久性的解决方案。用于测试和生产的xml作为富卖家post(谢谢!)

But need to change:

但是需要更改:

<copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>

for:

:

<move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>

In order persistence.xml.proper not embedded in .jar file

persistence . xml。正确的不嵌入。jar文件

#7


3  

Keep two copies of persistence.xml file. One for testing and another for normal build.

保留两份持久性。xml文件。一个用于测试,另一个用于正常构建。

The default life cycle copy the build persistence.xml to src/test/resources/META-INF

默认的生命周期复制构建持久性。xml到src / meta - inf /测试/资源

Create a separate profile which when run will copy the testing persistence.xml to src/test/resources/META-INF

创建一个单独的概要文件,运行时将复制测试持久性。xml到src / meta - inf /测试/资源

#8


3  

Persistence.xml is used as a starting point to search for entity classes unless you list all classes explicitly and add . So if you want to override this file with another one, say from src/test/resources, you have to specify every single entity class in this second persistence.xml otherwise no entity class would be found.

持久性。xml被用作搜索实体类的起点,除非您显式地列出所有类并添加。如果你想用另一个文件覆盖这个文件,比如从src/test/resources,你必须在第二个持久性中指定每个实体类。否则将不会找到任何实体类。

Another solution would be to overwrite the file using the maven-resources-plugin ('copy-resources' goal). But then you have to overwrite it twice, once for testing (e.g. phase process-test-classes) and once for the real packaging (phase 'prepare-package').

另一个解决方案是使用maven-resources-plugin(“copy-resources”目标)覆盖文件。但是您必须重写它两次,一次用于测试(例如阶段过程测试类),一次用于真正的打包(阶段“准备包”)。

#9


3  

This answer might sounds silly but I was looking for a way which lets me run those tests from eclipse by Run As -> JUnit Test. This is how I made it:

这个答案可能听起来很傻,但我正在寻找一种方法,可以让我以-> JUnit测试的形式从eclipse运行这些测试。我就是这样做的:

@BeforeClass
public static void setUp() throws IOException {
    Files.copy(new File("target/test-classes/META-INF/persistence.xml"), new File("target/classes/META-INF/persistence.xml"));
    // ...
}

I'm just copying the test/persistence.xml to classes/persistence.xml. This works.

我只是在复制测试/持久性。xml类/ persistence . xml。这个作品。

#10


1  

I'm trying to do the same thing. I have a solution that works for me - yours may vary (and you might not love the solution... it's a bit low-level).

我也在做同样的事情。我有一个适合我的解决方案——你的方案可能不同(你可能不喜欢这个方案……)这有点低级)。

I came across an article on the net where they were using a custom class loader to do something similar which served as inspiration. If anyone can see how to improve then suggestions would be welcome btw. For deployment I rely on container injection of the EntityManager but for testing I create it myself using this code:

我在网上看到一篇文章,他们使用自定义类装入器来做类似的事情,这可以作为灵感。如果有人能看到如何改进,那么建议将受到欢迎。对于部署,我依赖于EntityManager的容器注入,但是为了测试,我自己使用这个代码创建它:

final Thread currentThread = Thread.currentThread();
final ClassLoader saveClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(new ClassLoaderProxy(saveClassLoader));

EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("test");
em = emFactory.createEntityManager();

Then the ClassLoaderProxy is about as minimal as you can get and just redirects requests for META-INF/persistence.xml to META-INF/test-persist.xml:

然后ClassLoaderProxy就会尽可能地最小化,并且只需重定向对META-INF/持久性的请求。xml meta - inf / test-persist.xml:

public class ClassLoaderProxy extends ClassLoader {

    public ClassLoaderProxy(final ClassLoader parent) {
        super();
    }

    @Override
    public Enumeration<URL> getResources(final String name) throws IOException {
        if (!"META-INF/persistence.xml".equals(name)) {
            return super.getResources(name);
        } else {
            System.out.println("Redirecting persistence.xml to test-persist.xml");
            return super.getResources("META-INF/test-persist.xml");
        }
    }
}

Just to explain this a bit more:

再解释一下

  1. There are two persistence.xml files (one named persistence.xml that is used outside testing and one named test-persist.xml that is used for tests).
  2. 有两个持久性。xml文件(名为持久性)。用于外部测试和名为test-persist的xml。用于测试的xml)。
  3. The custom class loader is only active for unit tests (for deployment everything is normal)
  4. 自定义类装入器仅用于单元测试(对于部署来说,一切都是正常的)
  5. The custom class loader redirects requests for "META-INF/persistence.xml" to the test version ("META-INF/test-persist.xml").
  6. 自定义类装入器重定向“META-INF/持久性”请求。xml到测试版本(“META-INF/test- persistence .xml”)。

I was originally hitting some problems because Hibernate will revert back (somehow) to the classloader that was used to load Hibernate (at least I think that is what was going on). I've found that putting the ClassLoader switching code (the first block) as a static block in your Test case it will get loaded before Hibernate but that, depending on your unit test structure you may also need to put the same code in other places (yuck).

我最初遇到了一些问题,因为Hibernate会(以某种方式)恢复到用来装载Hibernate的类加载器(至少我认为是这样)。我发现将类加载器切换代码(第一个块)作为测试用例中的静态块将在Hibernate之前加载,但是根据单元测试结构,您可能还需要将相同的代码放在其他地方(呸)。

#11


1  

Another approach is to use a separate persistence.xml for testing (test/../META-INF/persistence.xml but override the Scanner as follows: -

另一种方法是使用单独的持久性。xml用于测试(测试/ . . / meta - inf /持久性。但覆盖扫描仪如下:-

testing persistence.xml needs to contain

测试的持久性。xml需要包含

<property name="hibernate.ejb.resource_scanner" value = "...TestScanner" />

<属性名= " hibernate.ejb。resource_scanner“价值="……TestScanner ">

Code for new class TestScanner is as follows.

新类TestScanner的代码如下所示。

import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import org.hibernate.ejb.packaging.NamedInputStream;
import org.hibernate.ejb.packaging.NativeScanner;


public class TestScanner extends NativeScanner
{

@Override
public Set <Class <?> > 
getClassesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getClassesInJar (getUpdatedURL (jar), annotations); }

@Override
public Set <NamedInputStream> 
getFilesInJar (URL jar, Set <String> patterns)
{  return super.getFilesInJar (getUpdatedURL (jar), patterns); }

@Override
public Set <Package> 
getPackagesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getPackagesInJar (getUpdatedURL (jar), annotations); }

private URL getUpdatedURL (URL url)
{
  String oldURL = url.toExternalForm ();
  String newURL = oldURL.replaceAll ("test-classes", "classes");
  URL result;
  try {
    result = newURL.equals (oldURL) ? url : new URL (newURL);
  } catch (MalformedURLException e)
  {  // Whatever  }
  return result;
}

}

#12


1  

Another option for this use case would be adding multiple persistence units, one for lets say production and another one for testing and inject the EntityManagerFactory accordingly.

这个用例的另一个选项是添加多个持久性单元,一个用于let say production,另一个用于测试和注入EntityManagerFactory。

Place both persistence-units into the persistence.xml of the actual project and have your test cases inject the correct EntityManager. The example below illustrates how to do that with guice. Please note that I've left in some mockito mocking for completeness, the mockito specific code has been marked accordingly and is not required for injection.

将两个持久化单元都放到持久性中。实际项目的xml,并让您的测试用例注入正确的EntityManager。下面的示例演示了如何使用guice实现这一点。请注意,我在一些mockito中留了一些mock作为完整性,mockito特定的代码已经被相应地标记,不需要注入。

public class HibernateTestDatabaseProvider extends AbstractModule {
    private static final ThreadLocal<EntityManager> ENTITYMANAGER_CACHE = new ThreadLocal<>();

    @Override
    public void configure() {
    }

    @Provides
    @Singleton
    public EntityManagerFactory provideEntityManagerFactory() {
        return Persistence.createEntityManagerFactory("my.test.persistence.unit");
    }

    @Provides
    public CriteriaBuilder provideCriteriaBuilder(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.getCriteriaBuilder();
    }

    @Provides
    public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {
        EntityManager entityManager = ENTITYMANAGER_CACHE.get();
        if (entityManager == null) {
            // prevent commits on the database, requires mockito. Not relevant for this answer
            entityManager = spy(entityManagerFactory.createEntityManager());


            EntityTransaction et = spy(entityManager.getTransaction());
            when(entityManager.getTransaction()).thenReturn(et);
            doNothing().when(et).commit();

            ENTITYMANAGER_CACHE.set(entityManager);
        }
        return entityManager;
    }
}

#13


0  

put tests in own maven project with its persistence.xml

将测试放在带有persistence.xml的maven项目中

#14


0  

When using OpenEJB, persistence.xml can be overriden with alternate descriptors: http://tomee.apache.org/alternate-descriptors.html

当使用OpenEJB、持久性。xml可以用替代描述符来覆盖:http://e.apache.org/e-descriptors.html。

#15


0  

I'd suggest using different maven profiles where you could filter your database.proprerties files and have one database.properties per profile.

我建议使用不同的maven配置文件来过滤数据库。proprerties文件和一个数据库。每个配置文件属性。

This way you don't have to keep duplicates of any other configuration files except for the .properties.

这样,除了.properties之外,您不必保留任何其他配置文件的副本。

<properties>
    <!-- Used to locate the profile specific configuration file. -->
    <build.profile.id>default</build.profile.id>
    <!-- Only unit tests are run by default. -->
    <skip.integration.tests>true</skip.integration.tests>
    <skip.unit.tests>false</skip.unit.tests>
    <integration.test.files>**/*IT.java</integration.test.files>
</properties>
<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>default</build.profile.id>
            <skip.integration.tests>true</skip.integration.tests>
            <skip.unit.tests>false</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file should be the default spring/database.properties file
                -->
                <filter>src/main/resources/META-INF/spring/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
    <profile>
        <id>integration</id>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>integration</build.profile.id>
            <skip.integration.tests>false</skip.integration.tests>
            <skip.unit.tests>true</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file is searched
                    from spring/profiles/it/ directory.
                -->
                <filter>src/main/resources/META-INF/spring/profiles/${build.profile.id}/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
</profiles>

With the help of surefire for unit tests and failsfe for integration tests, you're done.

在确保单元测试和集成测试失败的帮助下,您已经完成了。

    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <junitArtifactName>org.junit:com.springsource.org.junit</junitArtifactName>
        <!--see: https://issuetracker.springsource.com/browse/EBR-220-->
        <printSummary>false</printSummary>
        <redirectTestOutputToFile>true</redirectTestOutputToFile>
        <!-- Skips unit tests if the value of skip.unit.tests property is true -->
        <skipTests>${skip.unit.tests}</skipTests>
        <!-- Excludes integration tests when unit tests are run. -->
        <excludes>
            <exclude>${integration.test.files}</exclude>
        </excludes>
    </configuration>
</plugin>


<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <!-- Skips integration tests if the value of skip.integration.tests property is true -->
        <skipTests>${skip.integration.tests}</skipTests>
        <includes>
            <include>${integration.test.files}</include>
        </includes>
        <forkMode>once</forkMode>
        <!--
                            <reuseForks>false</reuseForks>
                            <forkCount>1</forkCount>
        -->
    </configuration>
    <executions>
        <execution>
            <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Now you need just mvn test for your unit tests and mvn verify -Pintegration for your integration tests. Obviously you should create the database.properties files in the specified (on the profiles) paths (or elsewhere and change the paths)

现在,您只需对单元测试进行mvn测试,并对集成测试进行mvn验证-Pintegration。显然,您应该创建数据库。指定(在概要文件上)路径中的属性文件(或其他地方并更改路径)

Based-on reference: http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

基于参考:http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

#16


0  

This is an extension of Rich Seller's answer with proper handling of Hibernate finding multiple persistence.xml files on the classpath and pre-testing state restoration.

这是富卖家的答案的扩展,正确地处理Hibernate,找到多重持久性。类路径上的xml文件和测试状态恢复。

Setup:

Create one persistence file for deployment/packaging and one for testing:

创建一个用于部署/打包的持久性文件和一个用于测试的持久性文件:

  • src/main/resources/persistence.xml

    src / main /资源/ persistence . xml

  • src/test/resources/persistence-testing.xml

    src /测试/资源/ persistence-testing.xml

in your pom.xml add this to the plugins section:

砰的一声。xml将其添加到插件部分:

        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
            <executions>
                <execution>
                    <id>copy-test-persistence</id>
                    <phase>process-test-resources</phase>
                    <configuration>
                        <tasks>
                            <echo>renaming deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
                            <echo>replacing deployment persistence.xml with test version</echo>
                            <copy file="${project.build.testOutputDirectory}/META-INF/persistence-testing.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>restore-persistence</id>
                    <phase>prepare-package</phase>
                    <configuration>
                        <tasks>
                            <echo>restoring the deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Advantages over other solutions

  • No extra Java code required
  • 不需要额外的Java代码
  • Only one persistence.xml on classpath
  • 只有一个持久性。xml在类路径中
  • Both building and testing work as expected
  • 构建和测试工作都和预期的一样。
  • Describing output on console (echo)
  • 描述控制台上的输出(echo)
  • For packaging the state is 100% restored. No leftover files
  • 包装状态100%恢复。没有剩下的文件