首页 > 解决方案 > 什么时候在测试中强制使用 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脚本按预期执行。

现在困惑是为什么

工作,但总是返回 1,为什么不 33 是​​如何预期的?

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

次要问题:

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

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

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

主要问题:

标签: spring-bootspring-boot-test

解决方案


根本问题与 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从来都不是强制性的。


推荐阅读