单元测试DAO因hsqldb和hibernate而失败

时间:2013-09-02 06:35:58

标签: java hibernate junit jpa-2.0

所以我整天都在解决这个问题,但我还是无法解决这个问题。如果我使用mysql在jboss 7中运行它,这是有效的。我创建了一个测试persistence.xml,它与我的一个连接属性不同,并且不使用jndi。

我试图让这段代码在本地运行,但是我遇到了问题,当我尝试使用PropertyAccessException持久化User实体时,我得到em.persist(myUser)堆栈跟踪显示hibernate试图将User.id类型long设置为(或a)User对象。

我不明白为什么会发生这种情况,请你解释为什么hibernate会混淆。

pom包含了所有应用程序依赖项,大多数可能都不相关,但我想我也可能在某个地方有一个重复的包。

我还查找了一些关于jboss中使用这些依赖项的版本的详细信息,如7.1.1.Final但运气不太好

的persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="testing" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <class>mypackage.beans.User</class>

    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        <property name="hibernate.hbm2ddl.auto" value="create"/>
        <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
        <property name="hibernate.connection.username" value="sa"/>
        <property name="hibernate.connection.password" value=""/>
        <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:test"/>
        <property name="hibernate.showSql" value="true"/>
        <property name="hibernate.archive.autodetection" value="true"/>
    </properties>
</persistence-unit>
</persistence>

实体

@Entity
@Table(name = "REPORTER")
public class User{

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "REPORTER_ID", nullable = false, unique = true)
private long id;

@Column(name = "REPORTER_USERNAME", nullable = false, unique = true)
private String username;

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getUsername() {
    return username;
}

public void setUsername(String username){
    this.username = username;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    User user = (User) o;

    if (id != user.id) return false;
    if (!username.equals(user.username)) return false;

    return true;
}

@Override
public int hashCode() {
    int result = (int) (id ^ (id >>> 32));
    result = 31 * result + username.hashCode();
    return result;
}
}

POM

<dependencies>
    <!-- resteay core library -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>2.3.2.Final</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson-provider</artifactId>
        <version>2.3.2.Final</version>
        <scope>provided</scope>
    </dependency>

    <!--Shiro Security Framework-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.2</version>
    </dependency>

    <!--joda time libs-->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.2</version>
    </dependency>

    <!-- twitter 4j core and streaming -->
    <dependency>
        <groupId>org.twitter4j</groupId>
        <artifactId>twitter4j-core</artifactId>
        <version>3.0.3</version>
    </dependency>

    <dependency>
        <groupId>org.twitter4j</groupId>
        <artifactId>twitter4j-stream</artifactId>
        <version>3.0.3</version>
    </dependency>

    <!-- validator for email-->
    <dependency>
        <groupId>commons-validator</groupId>
        <artifactId>commons-validator</artifactId>
        <version>1.4.0</version>
    </dependency>

    <!-- java ee api -->
    <dependency>
        <groupId>org.jboss.spec</groupId>
        <artifactId>jboss-javaee-6.0</artifactId>
        <version>3.0.2.Final</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>

    <!-- Hibernate Dependencies -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.1.6.Final</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.1.6.Final</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.3.1.Final</version>
        <scope>test</scope>
    </dependency>

    <!--mocking deps-->
    <dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>3.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.5.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-easymock</artifactId>
        <version>1.5.1</version>
        <scope>test</scope>
    </dependency>

    <!--Logging-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.15</version>
        <scope>test</scope>
    </dependency>

    <!-- hsqldb -->
    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>2.2.9</version>
        <scope>test</scope>
    </dependency>
</dependencies>

测试

@RunWith(PowerMockRunner.class)
@PrepareForTest(DaoLoader.class)
@PowerMockIgnore("javax.persistence.*")
public class UserParserTest {

private static EntityManagerFactory emf;
private UserParser parser;
private UserDao dao;
private EntityManager em;

@BeforeClass
public static void initializeEMF(){
    emf = Persistence.createEntityManagerFactory("testing");
}

@AfterClass
public static void closeEntityManagerFactory() {
    emf.close();
}

@Before
public void setUp() throws Exception {
    em = emf.createEntityManager();
    em.getTransaction().begin();
    dao = new UserDao(em);
    PowerMock.mockStatic(DaoLoader.class);
    EasyMock.expect(DaoLoader.loadDao("java:module/UserDao")).andReturn(dao);

    PowerMock.replay(DaoLoader.class);

    parser = new UserParser();
}

@After
public void rollbackTransaction() {
    if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
    }

    if (em.isOpen()) {
        em.close();
    }

    PowerMock.verify(DaoLoader.class);
}

@Test
public void testParse() throws Exception {
    parser.parse("test_username");
}

例外

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of mypackage.beans.User.id
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:871)
    at mypackage.dao.UserDao.getOrCreate(UserDao.java:39)
    at mypackage.filters.UserParser.parse(UserParser.java:26)
    at mypackage.filters.UserParserTest.testParse(UserParserTest.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
    Caused by: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of mypackage.beans.User.id
    at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:62)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:341)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4425)
    at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4147)
    at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:209)
    at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:495)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:118)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:844)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:819)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:823)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865)
    ... 35 more
    Caused by: java.lang.IllegalArgumentException: Can not set long field     mypackage.beans.User.id to mypackage.beans.User
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
    at sun.reflect.UnsafeLongFieldAccessorImpl.getLong(UnsafeLongFieldAccessorImpl.java:60)
    at sun.reflect.UnsafeLongFieldAccessorImpl.get(UnsafeLongFieldAccessorImpl.java:36)
    at java.lang.reflect.Field.get(Field.java:372)
    at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:59)
    ... 46 more

1 个答案:

答案 0 :(得分:0)

今天进一步测试后,我发现问题是由Powermock在没有dao直接测试Entity类并且模拟我的测试通过后引起的。一旦我在测试中添加了模拟失败。

我通过修改@PowerMockIgnore注释并添加所有JPA实体所在的包来修复此问题。这个测试现在通过了。

@RunWith(PowerMockRunner.class)
@PrepareForTest(DaoLoader.class)
@PowerMockIgnore({"javax.persistence.*","mypackage.beans.*"})
public class UserParserTest {

private static EntityManagerFactory emf;
private UserParser parser;
private UserDao dao;
private EntityManager em;

@BeforeClass
public static void initializeEMF(){
    emf = Persistence.createEntityManagerFactory("testing");
}

@AfterClass
public static void closeEntityManagerFactory() {
    emf.close();
}

@Before
public void setUp() throws Exception {
    em = emf.createEntityManager();
    em.getTransaction().begin();
    dao = new UserDao(em);
    PowerMock.mockStatic(DaoLoader.class);
    EasyMock.expect(DaoLoader.loadDao("java:module/UserDao")).andReturn(dao);

    PowerMock.replay(DaoLoader.class);

    parser = new UserParser();
}

@After
public void rollbackTransaction() {
    if (em.getTransaction().isActive()) {
        em.getTransaction().rollback();
    }

    if (em.isOpen()) {
        em.close();
    }

    PowerMock.verify(DaoLoader.class);
}

@Test
public void testParse() throws Exception {
    parser.parse("test_username");
}