69

デプロイに使用される通常のファイルの代わりにテストに使用されるように、Maven プロジェクトに 2 番目の persistence.xml ファイルをセットアップする方法はありますか?

私はpersistence.xmlをsrc/test/resources/META-INFに入れてみました。これはtarget/test-classes/META-INFにコピーされますが、target/classes/META-INFのようです(src/mainからのコピー/resources) が優先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
...

JPA 構成のデプロイメント バージョンを変更する必要なく、理想的にはプロジェクト チェックアウトの直後に、ローカルでの微調整を必要とせずに、単純な hsqldb 構成に対してテストを実行できるようにしたいと考えています。

4

17 に答える 17

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>

ここでは、/src/test/resources/META-INF/persistence.xml(copyed into target/test-classes) が (copyed into ) よりも優先/src/main/resources/META-INF/persistence.xmlされtarget/classesます。

残念ながら、persistence.xmlファイルの場所によって、いわゆる「永続化ユニットのルート@Entity」も決定されます。これにより、注釈をスキャンするクラスが決定されます。したがって、 を使用すると、 のクラスではなく、の/src/test/resources/META-INF/persistence.xmlクラスがスキャンされます (テストする必要があるクラスが存在する場所)。target/test-classestarget/classes

したがって、テストでは、 を避けるために、 に<class>エントリを明示的に追加する必要があります。のような別のファイル名を使用し、そのファイルを通常のファイルとまったく同じフォルダーに配置することで、エントリの必要性を回避できます。テスト フォルダーの Spring コンテキストは を参照するだけで、Spring は でそれを見つけます。persistence.xmljava.lang.IllegalArgumentException: Not an entity: class ...<class>persistence-TEST.xmlpersistence.xml<property name="persistenceXmlLocation" value="META-INF/persistence-TEST.xml" />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>
于 2010-06-01T11:55:40.120 に答える
13

複数のpersistence.xmlファイルはJPAの一般的な問題であり、クラスローディングのトリックによってのみ解決されるようです。

私にとって有効な回避策は、1 つの persistence.xml ファイルで複数の永続ユニットを定義し、展開とテスト コードで異なるバインディングを使用することです (Spring では、エンティティ マネージャー ファクトリで "persistenceUnitName" プロパティを設定できます)。テスト構成で展開ファイルを汚染しますが、問題なく動作することを気にしない場合。

于 2008-12-22T05:34:30.427 に答える
11

テスト用の/src/test/resources/META-INF/persistence.xml persistance.xml を追加します。@Arjan が言ったように、永続化ユニットのルートが変更され、エンティティ クラスが target/test-classes でスキャンされます。これを処理するには、 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>

次に、テスト リソースのフィルタリングを pom.xml に追加します。

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

これは、jar-fileが jar ファイルだけでなくディレクトリをターゲットにできるため、機能します。

于 2015-12-06T08:52:44.007 に答える
6

ClassLoaderProxy アプローチを試しましたが、JPA アノテーション付きクラスが hibernate によって永続クラスとして処理されないという問題がありました。

そこで、persistence.xml を使用せずに試してみることにしました。利点は、Maven ビルドと Eclipse JUnit テストが変更なしで機能することです。

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

私のテスト クラスは PersistenceTestSupport を拡張し、TestCase.setup() で setup() を呼び出すだけです。

唯一の欠点は、永続クラスを最新の状態に保つことですが、JUnit テストではこれで問題ありません。

于 2011-03-31T15:38:41.453 に答える
6

Rich Sellerの投稿として、テスト用と本番用に異なる persistence.xml を使用するソリューションを好みます(ありがとう!!)。

しかし、変更する必要があります:

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

為に:

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

persistence.xml.proper が .jar ファイルに埋め込まれていないため

于 2009-12-11T18:50:28.533 に答える
4

Run Asこの答えはばかげているように聞こえるかもしれませんが、これらのテストを Eclipse から->で実行できる方法を探していましたJUnit Test。これは私がそれを作った方法です:

@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"));
    // ...
}

test/persistence.xml を classes/persistence.xml にコピーしているだけです。これは機能します。

于 2014-11-04T11:11:51.467 に答える
3

Persistence.xml は、すべてのクラスを明示的にリストして . したがって、このファイルを別のファイル (src/test/resources など) でオーバーライドする場合は、この 2 番目の persistence.xml ですべてのエンティティ クラスを指定する必要があります。そうしないと、エンティティ クラスが見つかりません。

別の解決策は、maven-resources-plugin ('copy-resources' ゴール) を使用してファイルを上書きすることです。ただし、1 回目はテスト用 (例: フェーズ process-test-classes)、もう 1 回は実際のパッケージング用 (フェーズ 'prepare-package') です。

于 2009-06-22T10:41:56.680 に答える
3

persistence.xml ファイルの 2 つのコピーを保持します。1 つはテスト用、もう 1 つは通常のビルド用です。

デフォルトのライフ サイクルでは、ビルドの persistence.xml を src/test/resources/META-INF にコピーします。

実行時にテスト用の persistence.xml を src/test/resources/META-INF にコピーする別のプロファイルを作成します。

于 2008-12-22T04:18:39.750 に答える
1

私は同じことをしようとしています。私には自分に合った解決策があります-あなたの解決策は異なるかもしれません(そしてあなたはその解決策を気に入らないかもしれません...それは少し低レベルです)。

ネット上で、カスタムクラスローダーを使用して同様のことを行い、インスピレーションを得ているという記事に出くわしました。誰かが改善する方法を見ることができれば、提案はところで歓迎されるでしょう。デプロイメントではEntityManagerのコンテナーインジェクションに依存しますが、テストでは次のコードを使用して自分で作成します。

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

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

次に、ClassLoaderProxyは可能な限り最小限に抑えられ、META-INF/persistence.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");
        }
    }
}

これをもう少し説明するために:

  1. 2つのpersistence.xmlファイルがあります(1つはテスト外で使用されるpersistence.xmlという名前で、もう1つはテストに使用されるtest-persist.xmlという名前です)。
  2. カスタムクラスローダーは、単体テストでのみアクティブになります(展開の場合はすべて正常です)
  3. カスタムクラスローダーは、「META-INF / persistence.xml」の要求をテストバージョン(「META-INF / test-persist.xml」)にリダイレクトします。

Hibernateが(どういうわけか)Hibernateのロードに使用されたクラスローダーに戻るため(少なくともそれが起こっていたと思います)、私はもともといくつかの問題にぶつかっていました。ClassLoaderスイッチングコード(最初のブロック)を静的ブロックとしてテストケースに配置すると、Hibernateの前に読み込まれることがわかりましたが、単体テストの構造によっては、他の場所にも同じコードを配置する必要がある場合があります(うん)。

于 2009-07-21T12:02:20.120 に答える
1

もう 1 つの方法は、テスト用に個別の persistence.xml を使用することです (test/../META-INF/persistence.xml で、次のようにスキャナーをオーバーライドします)。

テストの persistence.xml には含まれている必要があります

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

新しいクラス 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;
}

}
于 2012-05-08T15:01:52.853 に答える
1

OpenEJB を使用する場合、persistence.xml は代替記述子でオーバーライドできます: http://tomee.apache.org/alternate-descriptors.html

于 2013-06-28T13:13:43.987 に答える
0

database.properties ファイルをフィルタリングし、プロファイルごとに 1 つの database.properties を持つことができるさまざまな Maven プロファイルを使用することをお勧めします。

このようにして、.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>

単体テスト用のsurefireと統合テスト用のfailsfeの助けを借りて、あなたは完了です.

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

mvn testこれで、単体テストとmvn verify -Pintegration統合テストだけが必要になります。明らかに、指定された (プロファイル上の) パス (または別の場所にあるパスを変更して) に database.properties ファイルを作成する必要があります。

参照に基づく: http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

于 2014-10-01T14:11:39.967 に答える
0

persistence.xml を使用して独自の Maven プロジェクトにテストを配置する

于 2009-09-21T06:35:40.733 に答える