spring-boot - 什么时候在测试中强制使用 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.sql
和data-h2.sql
脚本按预期执行。
现在困惑是为什么
.createQuery("SELECT COUNT(*) FROM Persona p")
.createNativeQuery("SELECT COUNT(*) FROM persona")
工作,但总是返回 1,为什么不 33 是如何预期的?
“似乎”在TestEntityManager
某种程度上无法处理文件加载的数据data-h2.sql
。
次要问题:
- 这是预期的行为吗?
即使是,为什么返回 1 而不是 0?还是强制性的额外配置?
我阅读了一些关于主要来源的教程@DataJpaTest
,TestEntityManager
其中包括:
前者是切片测试,后者是EntityManager
for 测试的替代方案。在其他教程中,我看到了许多TestEntityManager
在同一个中使用persist
和稍后检索数据(对于 1 个或多个实体)的示例@Test
,因此插入是手动完成的。
主要问题:
- 那么什么时候需要使用
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
从来都不是强制性的。
推荐阅读
- java - 为什么我可以使用 Spring WebSocket STOMP(使用 Spring Security 和 Keycloak)订阅目的地,但我没有收到该用户的任何消息?
- swift - macOS NSView - 如何为左右两侧提供动态边距
- python - 使用组合复制列表中的项目
- twitter-bootstrap - offset-sm 遇到问题(引导程序 4)
- android - Android onQueryTextChange 不显示 UI 更改
- excel - 从列表中删除行
- php - 在 Laravel 中如何管理嵌套的身份验证系统?
- android-studio - 版本 28 是旧版支持的最新版本
- c# - Google Drive API C# 应用程序名称不变
- python - 如何以 django 形式上传 python 脚本并将其用于某些处理?