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

Man*_*dan 4 java spring-boot spring-boot-test

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

存储库定义为:

public interface PersonaRepository extends CrudRepository<Persona, String> {

}
Run Code Online (Sandbox Code Playgroud)

然后进行以下测试

@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
    }

}
Run Code Online (Sandbox Code Playgroud)

long count = personaRepository.count();
assertThat(count).isEqualTo(33);
Run Code Online (Sandbox Code Playgroud)

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

现在的困惑是为什么

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

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

“似乎”TestEntityManager在某种程度上不适用于文件加载的数据data-h2.sql

次要问题:

  • 这是预期的行为吗?

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

我读了一些关于@DataJpaTest和 的教程TestEntityManager,其中主要来源:

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

主要问题:

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

rie*_*pil 7

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

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

$ SELECT COUNT(*) FROM Person;

COUNT(*)  
----
4
Run Code Online (Sandbox Code Playgroud)

这就是为什么您必须.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));
Run Code Online (Sandbox Code Playgroud)

Spring Data JPA 在底层做了完全相同的事情.count()

public long count() {
    return (Long)this.em.createQuery(this.getCountQueryString(), Long.class).getSingleResult();
}
Run Code Online (Sandbox Code Playgroud)

您还可以直接注入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));
  }

}
Run Code Online (Sandbox Code Playgroud)

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