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

Posted

技术标签:

【中文标题】如何在单元测试期间注入 PersistenceContext?【英文标题】:How to inject PersistenceContext during unit testing? 【发布时间】:2010-09-27 20:35:48 【问题描述】:

这是我的 java 类:

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

这是单元测试:

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

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

【问题讨论】:

【参考方案1】:

如果没有像 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();
        
    

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

我必须在每个单元测试中“手动”进行这种注入,对吧? 没有 Spring 可以解析 @PersistenceContext 注释并将其注入您的 Finder 类。您只需从 FinderTest 中引用 ApplicationContext。【参考方案3】:

创建另一个包私有构造函数并仅添加 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;


【讨论】:

以上是关于如何在单元测试期间注入 PersistenceContext?的主要内容,如果未能解决你的问题,请参考以下文章

C#单元测试--如何使用moq.mock进行依赖注入

如何在单元测试期间测试所需的 argparse 参数?

Python:如何在单元(鼻子)测试期间忽略装饰器?

如何在单元测试期间覆盖 IQueryable 的 Contains 方法?

使用 ReSharper,如何在长时间运行的单元测试期间显示调试输出?

如何在单元测试期间通过 Thymeleaf 模板的身份验证