嵌入式 GlassFish 忽略 Maven 测试资源

发布于 2024-11-25 10:45:59 字数 1469 浏览 1 评论 0原文

我已经为几个会话 bean 编写了单元测试。我已将 Maven 设置为在 src/main/resources/META-INF 目录中包含 persistence.xml,该目录引用本地 MySQL 数据库以用于开发目的。我在 src/test/resources/META-INF 目录中有另一个 persistence.xml,它引用嵌入式 Derby 数据库 __default。测试部署到嵌入式 GlassFish 3.1 容器。

然而,当我运行测试时,出现以下错误:

java.lang.RuntimeException: javax.naming.NamingException: Lookup failed for 'jdbc/mylog' 

jdbc/mylog 是主目录中持久单元引用的 MySQL 数据库。它显然忽略了测试目录中的持久性单元,但我不知道为什么。

据我所知,Maven 正在正确设置类路径,测试类位于类之前,并且查看实际的 target/test-classes/META-INF 目录表明它复制了正确的嵌入式 Derby 持久性单元。

[DEBUG] Test Classpath :
[DEBUG]   C:\Users\Laurens\Documents\Projects\Mylog\target\test-classes
[DEBUG]   C:\Users\Laurens\Documents\Projects\Mylog\target\classes
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\eclipselink\2.2.0\eclipselink-2.2.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\javax.persistence\2.0.3\javax.persistence-2.0.3.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\org.eclipse.persistence.jpa.modelgen.processor\2.2.0\org.eclipse.persistence.jpa.modelgen.processor-2.2.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\glassfish\extras\glassfish-embedded-all\3.1\glassfish-embedded-all-3.1.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\javax\javaee-web-api\6.0\javaee-web-api-6.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\junit\junit\4.8.1\junit-4.8.1.jar

非常感谢任何关于如何让 GlassFish 使用正确的持久性单元的提示!谢谢!

I have several session beans that I have written unit tests for. I have setup Maven to include a persistence.xml in the src/main/resources/META-INF directory that refers to a local MySQL database for development purposes. I have another persistence.xml in src/test/resources/META-INF directory that refers to the embedded Derby database __default. The tests are deployed to an embedded GlassFish 3.1 container.

When I run the tests however, I get the following error:

java.lang.RuntimeException: javax.naming.NamingException: Lookup failed for 'jdbc/mylog' 

jdbc/mylog is the MySQL database that the persistence unit in the main directory refers to. It is obviously ignoring the persistence unit in the test directory but I have no clue as to why.

Maven is setting the classpath correctly as far as I can tell, with test-classes before classes and a peek in the actual target/test-classes/META-INF directory reveals that it copied the correct, embedded Derby, persistence unit.

[DEBUG] Test Classpath :
[DEBUG]   C:\Users\Laurens\Documents\Projects\Mylog\target\test-classes
[DEBUG]   C:\Users\Laurens\Documents\Projects\Mylog\target\classes
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\eclipselink\2.2.0\eclipselink-2.2.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\javax.persistence\2.0.3\javax.persistence-2.0.3.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\eclipse\persistence\org.eclipse.persistence.jpa.modelgen.processor\2.2.0\org.eclipse.persistence.jpa.modelgen.processor-2.2.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\org\glassfish\extras\glassfish-embedded-all\3.1\glassfish-embedded-all-3.1.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\javax\javaee-web-api\6.0\javaee-web-api-6.0.jar
[DEBUG]   C:\Users\Laurens\.m2\repository\junit\junit\4.8.1\junit-4.8.1.jar

Any hint on how to have GlassFish use the proper persistence unit very much appreciated! Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

说不完的你爱 2024-12-02 10:45:59

使用嵌入式 Glassfish 运行测试时,JPA 提供程序在执行 maven-surefire-plugin 目标(用于运行测试阶段)之前不使用命令行上显示的类路径。嵌入式 Glassfish 将测试范围内可用的工件部署为 ScatteredArchive。此分散存档通常在 java.io.tmpdir 目录中创建,通常名称为 gfembedtmp,除非嵌入式 Glassfish 配置指定了 Glassfish 安装的位置root 和 Glassfish 域。

当嵌入式 Glassfish 域准备好部署的分散存档时,要部署的文件通常会复制到分解目录中,该目录包含应用程序所需的所有类(包括所有依赖项)。此目录通常恰好出现在 GF_EMBED_DOMAIN_HOME/applications/ 目录中。复制 src/main/resources/META-INFsrc/test/resources/META-INF 目录中的 persistence.xml 文件进入 /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 域配置文件的内容与嵌入式 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>
  ...
...

默认的domain.xml 文件可以从java.net 站点下载并进行修改(如果您希望尽可能减少更改),而不是从Glassfish 安装中复制文件。

2.复制 persistence.xml 文件

可以将目标添加到 Maven POM 文件,以从 src/test/resources/META-INF 备份和复制 persistence.xml 文件 到 src/main/resources/META-INF,在 test 阶段之前。测试阶段完成后,将恢复原始状态。我不会详细介绍这一点,因为 相关的 StackOverflow 问题。我没有使用这种方法进行集成测试,因为我需要进行的更改超出了 persistence.xml 中可以携带的更改,例如创建自定义领域。然而,我将它用于单元测试,因为 JPA 提供程序将从 target/classes 而不是 target/test 获取 persistence.xml 文件-classes,尽管后者在类路径顺序中首先出现。如果您使用 Hibernate 作为 JPA 提供程序,为 org.hibernate.ejb 记录器启用 TRACE 日志记录(因为 Ejb3Configuration 类负责执行查找)将使您确信test-classes 中的文件将不会被选取。


注意:

大部分答案都假设 Glassfish 3.1,但也可能适用于即将推出的版本。

When running tests using embedded Glassfish, the JPA provider does not use the classpath displayed on the command-line, before executing the maven-surefire-plugin goal (that is used to run the test phase). Embedded Glassfish deploys the artifacts that are available as part of a test scope, as a ScatteredArchive. This scattered archive is typically created in the java.io.tmpdir directory usually with the name gfembed<a_random_number>tmp, unless the embedded Glassfish configuration specified the location of a Glassfish installation root, and a Glassfish domain.

When the embedded Glassfish domain is prepared with the deployed scattered archive, the files to be deployed are typically copied into an exploded directory that houses all the classes (including all dependencies) required by the application. This directory typically happens to be present in the GF_EMBED_DOMAIN_HOME/applications/<application_name> directory. The persistence.xml files from your src/main/resources/META-INF and src/test/resources/META-INF directories are copied here into the <application-name>/META-INF directory. Needless to state, the one that gets copied last, or the one that doesn't get overwritten is the one that is used by the JPA provider during the tests. This always happens to be the file in src/main/resources/META-INF.

You can overcome this situation in two ways:

1. Using a custom Glassfish domain configuration file

You can specify a domain configuration file (domain.xml) that will contain the datasource definition for jdbc/mylog. This is what I do currently for it is very flexible and the domain configuration file can contain other configurations as well. The config file, needs to specified as part of test setup in the following way:

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.

The afore-mentioned glassfish-install directory and its sub-directory glassfish are present in the Maven project root (and also checked into version control); the glassfish directory must contain a directory structure of domain1/config to represent the directory structure of the Glassfish domain of name domain1. The structure in the project can be seen in the below screenshot. The other related files (the JDBC resource adapter JARs and the like), can be obtained from a Glassfish installation directory, but typically these might also be placed in the correct location by the embedded Glassfish runtime, if configured correctly.

Glassfish domain configuration file location

The contents of the Glassfish domain configuration file are different from the default one used by embedded Glassfish, except for the datasource and connection pool configuration (the relevant entries added in my usecase where I perform integration tests, have been posted below):

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

The default domain.xml file can be downloaded from the java.net site, and modified, in the event you wish to keep the changes as minimal as possible, instead of copying one from a Glassfish installation.

2. Copying over the persistence.xml files

One can add goals to the Maven POM file, to backup and copy the persistence.xml file from src/test/resources/META-INF to src/main/resources/META-INF, before the test phase. After the test phase is complete, the original is restored. I will not go into details of this, as a similar solution is already discussed in a related StackOverflow question. I did not use this approach for integration tests as I required changes to be done beyond the ones that can be carried in persistence.xml, like creation of a custom realm. I use it for unit-tests however, due to the fact that the JPA provider will fetch the persistence.xml file from target/classes instead of target/test-classes, despite the latter appearing first in the classpath order. If you use Hibernate as your JPA provider, enabling TRACE logging for the org.hibernate.ejb logger (as the Ejb3Configuration class is responsible for performing the lookup) would convince you that file in test-classes will not be picked up.


Note:

Most of the answer assumes Glassfish 3.1 but may hold good for upcoming versions as well.

蝶舞 2024-12-02 10:45:59

“嵌入式 glassfish 容器”是指为您运行 glassfish 的 Maven 插件吗? Maven 插件的类路径与 Maven 测试类路径不同且管理方式不同。您可能需要使用不同的类路径。

By "embedded glassfish container", do you mean a maven plugin that runs glassfish for you? The classpath for a maven plugin is different and managed differently than the maven test classpath. You might need to be working with a different classpath.

陈年往事 2024-12-02 10:45:59

这个答案可能听起来很愚蠢,但我一直在寻找一种方法,让我可以通过 Run As -> 从 Eclipse 运行这些测试。 JUnit 测试。这就是我的制作方法:

@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。这有效。

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:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文