当前位置: 动力学知识库 > 问答 > 编程问答 >

java - How can I reliably unit test updates of a JPA entity in a unit test

问题描述:

I have this test setup where I'm using spring, derby and JPA and I want to test whether updates work.

I can't really do this in the standard way, that is. Create an entity object, persist, find object again, change some field in the object, persist again, do a find to see whether it has changed.

The problem with that approach is that I don't get a new instance of the entity. It is always the same. So I can't really tell if update works correctly because I am always changing the same object, so any change is reflected prematurely.

If I make a change to some object without merging it with the persistencecontext, and then try to do a find on that object, the change is already present in the find as it is always working with the same object.

Is there any way I can lose the context and do a real test that updating is working correctly?

Here is my current code:

@Test

public void canUpdate() {

JsonTestEntity entity1 = new JsonTestEntity();

JsonTestEntity entity2 = new JsonTestEntity();

String message = "OmegaCV1";

String message2 = "OmegaCV2";

entity1.setMessage(message);

entity2.setMessage(message2);

em.persist(entity1);

em.persist(entity2);

em.flush();

JsonTestEntity jsonTestEntity = em.find(JsonTestEntity.class, entity2.getId());

assertNotNull("Could not find persisted entity", jsonTestEntity);

assertEquals("Was not same entity", message2, jsonTestEntity.getMessage());

String changeMessage = "Changed message";

jsonTestEntity.setMessage(changeMessage);

JsonTestEntity unChangedEntity = em.find(JsonTestEntity.class, entity2.getId());

assertEquals("Message was prematurely changed", message2, unChangedEntity.getMessage());

em.merge(jsonTestEntity);

JsonTestEntity changedEntity = em.find(JsonTestEntity.class, entity2.getId());

assertEquals("Message was not changed", changeMessage, changedEntity.getMessage());

}

网友答案:

If there was a possibility to disable EntityManager's 1st level cache - it would solve your problem :)

So I have a few ideas :

  1. If your EntityManager is per-transaction - just do the persist() and find() in different transactions.

  2. Use em.clear() - it will detach all managed entities. Don't forget to em.flush() before this to commit the changes.

  3. If you use Hibernate - clear the Session after persist().flush() it before :

    Session session = em.unwrap(Session.class); session.flush(); session.clear();

  4. Also you can reload the entity's state using Session.refresh()

Docs :

  • http://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html
  • http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html
网友答案:

Another alternative I have seen used in unit tests is to use a native query which will be guaranteed to straight to the database.

Query query = em.createNativeQuery("select ... from ....");
List list = query.getResultList(); // or getSingleResult();

which will return a List of Object []

网友答案:

It is usually pretty frustrating to get JPA to "dumb-down" and read the database again.

I think you can get what you want by calling EntityManager.refresh(entity2);

You can also add @Cacheable(false)to JsonTestEntity class. Of course this has the big disadvantage that you have to put it back later.

网友答案:

So here is how to fix it:

@Test
public void canUpdate() {

    JsonTestEntity entity1 = new JsonTestEntity();
    JsonTestEntity entity2 = new JsonTestEntity();

    String message = "OmegaCV1";
    String message2 = "OmegaCV2";

    entity1.setMessage(message);
    entity2.setMessage(message2);

    em.persist(entity1);
    em.persist(entity2);

    em.clear(); // Clears the entitymanager so jsonTestEntity != entity2

    JsonTestEntity jsonTestEntity = em.find(JsonTestEntity.class, entity2.getId());

    assertNotNull("Could not find persisted entity", jsonTestEntity);
    assertEquals("Was not same entity", message2, jsonTestEntity.getMessage());

    String changeMessage = "Changed message";
    jsonTestEntity.setMessage(changeMessage);

    em.clear(); // same reason as above, I cannot however use flush here as that would commit the changed message

    JsonTestEntity unChangedEntity = em.find(JsonTestEntity.class, entity2.getId());

    assertEquals("Message was prematurely changed", message2, unChangedEntity.getMessage());
    em.merge(jsonTestEntity);

    em.flush(); // since merge performs an update in this case, I need to flush to commit the update, after the flush --> unchangedEntity.getMessage().equals(jsonTestEntity.getMessage())
    em.clear(); // I clear again to get separate objects

    JsonTestEntity changedEntity = em.find(JsonTestEntity.class, entity2.getId());
    assertEquals("Message was not changed", changeMessage, changedEntity.getMessage());


}
分享给朋友:
您可能感兴趣的文章:
随机阅读: