【问题标题】:JUnit, JPA, Hibernate and Postgres: How to test?JUnit、JPA、Hibernate 和 Postgres:如何测试?
【发布时间】:2012-07-23 00:55:58
【问题描述】:

我已经被困了一段时间了。我进行了很多搜索,但找不到针对 postgres 数据库测试实体类或 JPA 操作的最简单方法。我已经找到了如何使用 Spring、Mockito 和其他东西,但我找不到使用纯 Java 的最简单方法。

我有以下 JUnit 测试:

public class ModelConverterTest {

    private static EntityManagerFactory emf;
    private static EntityManager em;


    public ModelConverterTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
        emf = Persistence.createEntityManagerFactory("PU");
        em = emf.createEntityManager(); // Retrieve an application managed entity manager
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
        em.close();
        emf.close(); //close at application end
    }

    @Before
    public void setUp() {
         ...    
    }

    @After
    public void tearDown() {
    }

    /**
     * Test of SIMModelToModel method, of class ModelConverter.
     */
    @Test
    public void testSIMModelToModel() {
        System.out.println("SIMModelToModel");
        SIMModel simModel = new PESMModel();
        simModel.addState(testState);
        Model expResult = null;
        Model result = ModelConverter.SIMModelToModel(em, simModel);
        assertTrue(expResult!=null);
        // TODO review the generated test code and remove the default call to fail.
        //fail("The test case is a prototype.");
    }
}

运行时出现以下错误:

java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/persistence/PersistenceContextType
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:787)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:447)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
    at java.lang.Class.getDeclaredMethods(Class.java:1808)
    at sun.reflect.annotation.AnnotationType$1.run(AnnotationType.java:104)
    at sun.reflect.annotation.AnnotationType$1.run(AnnotationType.java:101)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.reflect.annotation.AnnotationType.<init>(AnnotationType.java:100)
    at sun.reflect.annotation.AnnotationType.getInstance(AnnotationType.java:84)
    at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:221)
    at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:88)
    at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:70)
    at java.lang.reflect.Field.declaredAnnotations(Field.java:1033)
    at java.lang.reflect.Field.getDeclaredAnnotations(Field.java:1026)
    at java.lang.reflect.AccessibleObject.getAnnotations(AccessibleObject.java:196)
    at org.junit.runners.model.FrameworkField.getAnnotations(FrameworkField.java:26)
    at org.junit.runners.model.TestClass.addToAnnotationLists(TestClass.java:52)
    at org.junit.runners.model.TestClass.<init>(TestClass.java:45)
    at org.junit.runners.ParentRunner.<init>(ParentRunner.java:73)
    at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:55)
    at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:13)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:51)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)

我的 persistence.xml 文件是:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 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">
  <persistence-unit name="PU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/modelsystemdb</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>

我应该怎么做才能使测试运行?

【问题讨论】:

  • 如果您使用的是真正的 JPA 提供程序,而不是模拟接口,那么这不是单元测试,而是集成测试。这绝对没问题 - 但你不应该将其称为单元测试。
  • 你说得对,我编辑了问题。

标签: java hibernate jakarta-ee junit jpa-2.0


【解决方案1】:

引用 Adam Bien 的 Trouble With Crippled Java EE 6 APIs in Maven Repository And The Solution

而不是使用

<dependency>
  <groupId>javax</groupId>
  <artifactId>javaee-web-api</artifactId>
  <version>6.0</version>
  <scope>provided</scope>
</dependency>

您应该使用替代(geronimo、jboss 等)依赖项:

<dependency>
   <groupId>org.apache.geronimo.specs</groupId>
   <artifactId>geronimo-ejb_3.1_spec</artifactId>
   <version>1.0</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>org.apache.geronimo.specs</groupId>
   <artifactId>geronimo-jpa_2.0_spec</artifactId>
   <version>1.0</version>
   <scope>provided</scope>
</dependency>

【讨论】:

  • 谢谢!但我的 pom.xml 中没有包含该依赖项。我有javaee-api。试图删除它,但找不到完整的替代品。另外,我尝试了您给我和 Jboss 的那些依赖项,但没有奏效。虽然我正在使用 Glassfish,但也找不到替代包:S
  • javaee-api 可以用于编译,但您不能在运行时使用它。您必须从提供者那里获得适当的 API 实现。我使用 org.hibernate.javax.persistence:hibernate-jpa-2.0-api,它包含 JPA 2 API,仅此而已。即使您不使用 Hibernate,也可以使用它,因为它只是 API。
【解决方案2】:

有类似的问题。即,即使 Hibernate JPA jar 可通过传递依赖项获得,并且提供了 javaee 6.0 依赖项,JUNIT 测试用例也失败了。我只是在 pom 文件的依赖项定义末尾移动了 javaee 依赖项,以便在类路径解析期间休眠 JPA api jar 出现在 Javaee jar 之前。这似乎起到了作用,我能够运行测试用例。希望这会有所帮助。

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

hibernate依赖后出现javaee

<dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>6.0</version>
        <scope>provided</scope>
    </dependency>

【讨论】:

  • +1:我已经安装了同样的 bodge,javaee-api 在我的 POM 底部。很高兴将其缩小到 Hibernate 排序,现在我想起来似乎很明显。 :-)
【解决方案3】:

如果你想在你的测试中使用 JPA,那么当你运行它们时,你需要在类路径上有一个 JPA 提供者。您可以针对 javaee-api 进行编译,但您必须在运行时拥有一个真实的、实时的提供程序。

您提到您正在使用 GlassFish;它使用 EclipseLink 作为它的提供者,所以对你的测试做同样的事情对你来说是有意义的。在他们的 wiki 上有 information about using EclipseLink via Maven

【讨论】:

  • 感谢 Tom,但我希望让它与 hibernate 一起工作,这可能吗?
  • 当然!只需添加相关的 Hibernate 依赖项即可。我有 org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final 作为编译依赖,org.hibernate:hibernate-entitymanager:4.1.4.Final 作为运行时依赖。这些加上它们的传递依赖是我使用 Hibernate 所需要的。好吧,还有一个数据库驱动程序。还有某种日志后端,虽然实际上,我还没有弄清楚。
  • 对不起,Tom,非常感谢您抽出宝贵时间,但我已经安装了这些依赖项。如果不部署到 Glassfish,我找不到运行测试的方法。
  • 那里的所有注解也在org.hibernate.javax.persistence:hibernate-jpa-2.0-api中,所以如果你在你的编译类路径中有它,它们将被解析。如果它们没有被解析,那么它实际上不在你的类路径中。
  • 啊哈。在这种情况下,您要么需要找到其他来源,要么确保hibernate-jpa-2.0-api 在类路径上的优先级高于javaee-api。但实际上,javaee-api 只适合编译,不适合在运行时使用。
【解决方案4】:

我们有一个非常相似的问题:Junit 测试在 maven 构建期间成功执行,但是尝试从 Eclipse 直接运行它们显示了这个可怕的“缺少代码”错误。解决方案不在 pom.xml-s 中(它们必须是正确的,因为您的构建运行,对吧?),而是在 eclipse 中执行 Junit 的配置。在我们的例子中,当将 maven 依赖项移到项目本身之上时,会加载正确的实现(eclipselink 2.0.4)持久性类。因此,在 Eclipse 中尝试检查“运行配置...”,选择有问题的 Junit 配置,然后在“类路径”选项卡上,更改“用户条目”部分中库的顺序:将 Maven 依赖项移到顶部。

最好的问候, 乔公众

【讨论】:

    【解决方案5】:

    在我的情况下,在项目的运行配置/类路径下,单击编辑并选中“仅包含导出的条目”即可。

    【讨论】:

      猜你喜欢
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      • 2011-10-11
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-21
      相关资源
      最近更新 更多