什么时候在测试中强制使用 TestEntityManager?

问题描述

一个 Spring Boot 应用程序,使用 Spring Data JPA 和 H2 配置,它用于示例/学术目的。

存储库定义为:

public interface PersonaRepository extends CrudRepository<Persona,String> {

}

然后进行下面的测试

@ActiveProfiles(profiles={"h2"})
@DataJpaTest
class PersonaRepositorySliceTests {

    @Autowired
    private PersonaRepository personaRepository;

    @Autowired
    private TestEntityManager testEntityManager;

    @Test
    void counttest() {
        long count = personaRepository.count();
        assertthat(count).isEqualTo(33);

        count = testEntityManager.getEntityManager()
                                 .createquery("SELECT COUNT(*) FROM Persona p")
                                 .getResultList().size();
        System.out.println("count: " + count);//prints 1
        //assertthat(count).isEqualTo(33);//fails

        count = testEntityManager.getEntityManager()
                                 .createNativeQuery("SELECT COUNT(*) FROM persona")
                                 .getResultList().size();

        System.out.println("count: " + count);//prints 1
        assertthat(count).isEqualTo(33);//fails
    }

}

long count = personaRepository.count();
assertthat(count).isEqualTo(33);

通过,因此检测到 @Entity 类,当然 schema-h2.sqldata-h2.sql 脚本按预期执行。

现在困惑是为什么

  • .createquery("SELECT COUNT(*) FROM Persona p")
  • .createNativeQuery("SELECT COUNT(*) FROM persona")

有效但是总是返回 1,为什么不是 33 怎么会是预期的?

“似乎” TestEntityManager 在某种程度上不能处理 data-h2.sql 文件加载的数据。

次要问题:

  • 这是预期的行为吗?

即使是,为什么返回1而不是0?还是强制性的额外配置?

我阅读了一些关于 @DataJpaTestTestEntityManager 的教程,其中,主要来源:

前者是切片测试,后者是EntityManager的替代测试。 在其他教程中,我看到了许多 TestEntityManager 使用 persist 并随后在同一个 @Test 中检索数据(用于 1 个或多个实体)的示例,因此插入是手动完成的。>

主要问题:

  • 那么,出于测试目的,何时需要使用 TestEntityManager 类型(方法)而不是自定义 CrudRepository<T,ID> 方法

解决方法

根本问题与 Spring Boot/Hibernate 或您的测试设置无关。

SQL 语句 SELECT COUNT(*) FROM Person 返回单行,单列包含计数的行数:

$ SELECT COUNT(*) FROM Person;

COUNT(*)  
----
4

这就是您必须从原生或自定义查询的结果中调用 .getSingleResult() 的原因:

assertThat(personRepository.count())
  .isEqualTo(4);

assertThat(testEntityManager.getEntityManager()
                            .createQuery("SELECT COUNT(*) FROM Person p",Long.class)
                            .getSingleResult())
  .isEqualTo(4L);

assertThat(testEntityManager.getEntityManager()
                            .createNativeQuery("SELECT COUNT(*) FROM Person")
                            .getSingleResult())
  .isEqualTo(BigInteger.valueOf(4));

Spring Data JPA 为 .count() 做了完全相同的事情:

public long count() {
    return (Long)this.em.createQuery(this.getCountQueryString(),Long.class).getSingleResult();
}

您也可以直接为您的 EntityManager 测试注入 @DataJpaTest 而不需要 TestEntityManager

@DataJpaTest
class ApplicationTests {

  @Autowired
  private TestEntityManager testEntityManager;

  @Autowired
  private EntityManager entityManager;

  @Autowired
  private PersonRepository personRepository;

  @Test
  void contextLoads() {

    assertThat(personRepository.count())
      .isEqualTo(4);

    //With TestEntityManager

    assertThat(testEntityManager.getEntityManager()
                                .createQuery("SELECT COUNT(*) FROM Person p",Long.class)
                                .getSingleResult())
      .isEqualTo(4L);

    assertThat(testEntityManager.getEntityManager()
                                .createNativeQuery("SELECT COUNT(*) FROM Person")
                                .getSingleResult())
      .isEqualTo(BigInteger.valueOf(4));

     //With EntityManager

    assertThat(entityManager.createQuery("SELECT COUNT(*) FROM Person p",Long.class)
                            .getSingleResult())
      .isEqualTo(4L);

    assertThat(entityManager.createNativeQuery("SELECT COUNT(*) FROM Person")
                            .getSingleResult())
      .isEqualTo(BigInteger.valueOf(4));
  }

}

TestEntityManager 提供了辅助方法,例如使用单行执行持久/刷新/查找操作(刷新内存中的持久性上下文并从数据库中读取相同的实体)。 TestEntityManager 永远不是强制性