Java 如何在单元测试期间注入 PersistenceContext?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3807638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 05:21:05  来源:igfitidea点击:

How to inject PersistenceContext during unit testing?

javahibernateormjpa

提问by yegor256

This is my java class:

这是我的java类:

public class Finder {
  @PersistenceContext(unitName = "abc")
  EntityManager em;
  public boolean exists(int i) {
    return (this.em.find(Employee.class, i) != null);
  }
}

This is the unit test:

这是单元测试:

public class FinderTest {
  @Test public void testSimple() {
    Finder f = new Finder();
    assert(f.exists(1) == true);
  }
}

Testing fails with NullPointerExceptionsince Finder.emis not injected by anyone. How should I handle this situation properly? Does there any best practice exist?

测试失败,NullPointerException因为Finder.em不是由任何人注入的。我应该如何正确处理这种情况?是否存在任何最佳实践?

采纳答案by Pascal Thivent

Without a container like Spring (or something like Unitils- which is Spring based), you will have to inject the entity manager manually. In that case, you coulduse something like this as base class:

如果没有像 Spring 这样的容器(或类似Unitils——它是基于 Spring 的),你将不得不手动注入实体管理器。在这种情况下,你可以使用这样的东西作为基类:

public abstract class JpaBaseRolledBackTestCase {
    protected static EntityManagerFactory emf;

    protected EntityManager em;

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

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

    @Before
    public void beginTransaction() {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

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

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

回答by Richard Kettelerij

It depends on whatyou want to test. When you have complex business logic in your Finderclass you may want to mock the EntityManager- using a mocking framework like EasyMockor Mockito- in order to unit test that logic.

这取决于你想测试什么。当您的类中有复杂的业务逻辑时,您Finder可能想要模拟EntityManager- 使用像EasyMockMockito这样的模拟框架- 以便对该逻辑进行单元测试。

Now since that's not the case I suspect you want to test the persistency of the Employeeentity (this is often referred to as integration testing). This requires the use of a database. To make testing easy and keep your tests portable you can use an in-memory database like HSQLDBfor this purpose. In order to start HSQLDB, create a persistence context and inject this context into your Finder class it's advisable to use an IoC framework like Spring.

现在,由于情况并非如此,我怀疑您想要测试Employee实体的持久性(这通常称为集成测试)。这需要使用数据库。为了简化测试并保持测试的可移植性,您可以为此使用内存数据库,如HSQLDB。为了启动 HSQLDB,创建一个持久化上下文并将这个上下文注入到您的 Finder 类中,建议使用 IoC 框架,如Spring

There are tons of tutorials on the internet that explain how to use JPA/Spring/HSQLDB. Take a look at this example project: Integration testing with Maven 2, Spring 2.5, JPA, Hibernate, and HSQLDB

互联网上有大量教程解释如何使用 JPA/Spring/HSQLDB。看一下这个示例项目:Integration testing with Maven 2, Spring 2.5, JPA, Hibernate, and HSQLDB

回答by Ahmet Koylu

Create another package-private constructor and add only EntityManager then call the other constructor for default behavior.

创建另一个包私有构造函数并仅添加 EntityManager 然后调用另一个构造函数以获得默认行为。

@PersistentContext
private EntityManager entityManager;

private ManagementService managementService;

@Autowired
public SomeClass(ManagementService managementService) {
    this.managementService = managementService;
}

SomeClass(ManagementService managementService, EntityManager entityManager) {
    this(managementService);

    this.entityManager = entityManager;
}