使用嵌入式 Glassfish 运行测试时,JPA 提供程序在执行 maven-surefire-plugin 目标(用于运行测试阶段)之前不使用命令行上显示的类路径。 Embedded Glassfish 将作为测试范围的一部分可用的工件部署为ScatteredArchive。这个分散的存档通常创建在 java.io.tmpdir 目录中,通常名称为 gfembed<a_random_number>tmp,除非嵌入式 Glassfish 配置指定了 Glassfish 安装根目录和 Glassfish 域的位置。
当嵌入式 Glassfish 域准备好已部署的分散存档时,要部署的文件通常会复制到一个展开的目录中,该目录包含应用程序所需的所有类(包括所有依赖项)。该目录通常恰好出现在GF_EMBED_DOMAIN_HOME/applications/<application_name> 目录中。您的src/main/resources/META-INF 和src/test/resources/META-INF 目录中的persistence.xml 文件在此处复制到<application-name>/META-INF 目录中。不用说,最后被复制的那个,或者没有被覆盖的那个是 JPA 提供者在测试期间使用的那个。这总是恰好是src/main/resources/META-INF 中的文件。
您可以通过两种方式克服这种情况:
1.使用自定义 Glassfish 域配置文件
您可以指定一个域配置文件 (domain.xml),其中将包含 jdbc/mylog 的数据源定义。这是我目前所做的,因为它非常灵活,域配置文件也可以包含其他配置。配置文件,需要通过以下方式指定为测试设置的一部分:
Map<String, Object> props = new HashMap<String, Object>();
props.put("org.glassfish.ejb.embedded.glassfish.installation.root", "./glassfish-install/glassfish");
container = EJBContainer.createEJBContainer(props);
context = container.getContext();
datasource = (DataSource) context.lookup("jdbc/mylog"); //You can lookup the datasource too, to confirm that your setup is successful.
上述glassfish-install 目录及其子目录glassfish 存在于Maven 项目根目录中(并且也已签入版本控制); glassfish 目录必须包含 domain1/config 的目录结构,以表示名称为 domain1 的 Glassfish 域的目录结构。项目中的结构可以在下面的屏幕截图中看到。其他相关文件(JDBC 资源适配器 JAR 等)可以从 Glassfish 安装目录中获得,但如果配置正确,通常这些文件也可能由嵌入式 Glassfish 运行时放置在正确的位置。
Glassfish 域配置文件的内容与嵌入式 Glassfish 使用的默认配置文件不同,除了数据源和连接池配置(在我执行集成测试的用例中添加的相关条目已在下面发布):
<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0">
<system-applications/>
<applications/>
<resources>
<jdbc-resource pool-name="MyPool" jndi-name="jdbc/mylog"/>
...
<jdbc-connection-pool driver-classname="" datasource-classname="org.apache.derby.jdbc.ClientDataSource" res-type="javax.sql.DataSource" description="" name="MyPool" ping="true">
<property name="User" value="APP"></property>
<property name="RetrieveMessageText" value="true"></property>
<property name="CreateDatabase" value="true"></property>
<property name="ServerName" value="localhost"></property>
<property name="Ssl" value="off"></property>
<property name="SecurityMechanism" value="4"></property>
<property name="TraceFileAppend" value="false"></property>
<property name="TraceLevel" value="-1"></property>
<property name="PortNumber" value="1527"></property>
<property name="LoginTimeout" value="0"></property>
<property name="Password" value="APP"></property>
<property name="databaseName" value="MYDB"></property>
</jdbc-connection-pool>
...
</resources>
<servers>
<server name="server" config-ref="server-config">
<resource-ref ref="jdbc/__TimerPool"/>
<resource-ref ref="jdbc/__default"/>
<resource-ref ref="jdbc/mylog"/>
</server>
</servers>
...
...
default domain.xml file can be downloaded from the java.net site 已修改,如果您希望尽可能减少更改,而不是从 Glassfish 安装中复制一个。
2。复制 persistence.xml 文件
可以在 Maven POM 文件中添加目标,在test 阶段之前将persistence.xml 文件从src/test/resources/META-INF 备份和复制到src/main/resources/META-INF。测试阶段完成后,恢复原件。我不会对此进行详细介绍,因为a related StackOverflow question 已经讨论了类似的解决方案。我没有将这种方法用于集成测试,因为我需要在persistence.xml 中进行的更改之外进行更改,例如创建自定义领域。然而,我将它用于单元测试,因为 JPA 提供程序将从 target/classes 而不是 target/test-classes 获取 persistence.xml 文件,尽管后者首先出现在类路径顺序中。如果您使用 Hibernate 作为您的 JPA 提供程序,为 org.hibernate.ejb 记录器启用 TRACE 日志记录(因为 Ejb3Configuration 类负责执行查找)将使您确信 test-classes 中的文件不会被拾取。
注意:
大部分答案都假设 Glassfish 3.1,但也可能适用于即将推出的版本。