如何在内存数据库中使用 H2 测试 EntityManager 查询
Posted
技术标签:
【中文标题】如何在内存数据库中使用 H2 测试 EntityManager 查询【英文标题】:How to test EntityManager query with H2 in memory DB 【发布时间】:2022-01-23 18:58:24 【问题描述】:我有一个 Spring Boot 项目,我想测试一些查询。我想插入一组预定义的数据并执行存储库查询以检查结果是否是所需的。
为此,我使用的是内存 H2 DB,但问题(我认为)不存在,与 DB 相关的一切都正常。主要问题是我无法正确模拟存储库中的EntityManager
字段,并且查询始终为空。
我的仓库是这样的:
@Repository
public class MyRepositoryImpl implements MyRepository
@PersistenceContext
private EntityManager entityManager;
@Override
public Result runQuery()
TypedQuery<Result> query = entityManager.createQuery(
"SELECT ...", Result.class);
return query.setParameter("...", "...") // here 'query' is always null
.setMaxResults(1)
.getResultStream()
.findFirst()
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Entity not found"));
在测试之外执行时效果很好,但是尝试运行此测试文件会引发错误:
@RunWith(SpringRunner.class)
public class MyRepositoryTest
@Mock
EntityManager entityManager;
@InjectMocks
MyRepositoryImpl repository;
@Test
public void it_should_works()
Result r = repository.runQuery();
assertNull(r);
存储库被模拟并且不为空,我可以调用该方法。但是在仓库内部,由于query
字段为空,尝试执行时会抛出NullPointerException
。
我在互联网上搜索了很多方法来测试界面内的JPARepository
和@Query
,但不是EntityManager
查询。
我还找到了一些模拟查询结果的方法,比如when(runQuery()).thenReturn(result)
,但我不希望这样,我在内存数据库中有数据,所以我想执行查询并获取结果。
所以,现在,我认为的主要问题是如何在存储库类中正确地模拟 EntityManager
对象。
提前致谢。
编辑:
我已经关注 this link 并且就像另一个 SO 问题:这只是为了模拟 JpaRepository
。
我用过这段代码:
@Test
public void it_should_works()
Result r = repository.findAll();
assertNotNull(r);
而且效果很好,但是使用我自己的查询失败并出现错误:
org.springframework.orm.jpa.JpaSystemException: could not advance using next(); nested exception is org.hibernate.exception.GenericJDBCException: could not advance using next()
...
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: El objeto ya está cerrado
The object is already closed [90007-200]
所以问题是:它与我的数据库有关吗?为什么使用 JpaRepository 方法它可以工作,但我自己的查询却不行?
编辑:
解决了将@Transactional
添加到存储库的问题。
【问题讨论】:
【参考方案1】:由于您使用 h2 内存数据库来运行测试,并且您希望在测试中实际使用该数据库,因此您不应该真正模拟任何东西。
您的模拟不起作用,因为 MyRepositoryImpl 通常由 Spring 初始化,并且该过程比插入 EntityManager 复杂得多。
我认为你想做的更像是这里描述的https://www.baeldung.com/spring-testing-separate-data-source
因此,您将拥有一个覆盖数据源属性的 src/test/resources/application.properties 文件。然后,您只需像往常一样将您的存储库 @Autowired 到您的测试类中。
【讨论】:
以上是关于如何在内存数据库中使用 H2 测试 EntityManager 查询的主要内容,如果未能解决你的问题,请参考以下文章
使用 JPA 和 JUnit 测试时如何一致地擦除内存数据库中的 H2 [重复]