java - 使用 createQuery()、参数和 executeUpdate() 模拟 Hibernate entityManager
问题描述
我是 Java 单元测试的新手;我有一个使用 Hibernate 与 MySQL 数据库交互的应用程序。
我有许多使用createQuery()
方法构建的查询,也带有参数,如下所示:
return this.entityManager.createQuery("from MyEntity m where param = :param", MyEntity.class)
.setParameter("param", param)
.getSingleResult();
我想避免模拟entityManager
对象上的所有后续调用,因为有时我使用超过 5 个参数进行查询,并且模拟每个调用似乎并不那么方便。
相同的概念可以应用于Builder 对象。
编辑 1
我添加了一个我使用的具体示例(鉴于这不是管理异常的好方法,但不幸的是通常很安静):
public class MyService {
private EntityManager entityManager;
public MyEntity find(String field ) {
try{
return this.entityManager.createQuery("from MyEntity c where c.field = :field ", MyEntity .class)
.setParameter("field ", field )
.getSingleResult();
} catch (NoResultException e) {
return null;
} catch (NonUniqueResultException e) {
logger.error("find", e);
return null;
}
}
}
在这个例子中,考虑到调用的行为,entityManager
我有不同的分支要测试。然后我必须模拟那个调用的答案来测试这个方法的所有行。
我发现了什么
我发现如下:
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private EntityManager entityManager;
哪个按预期工作。我可以模拟所有调用链。但
警告:常规干净代码很少需要此功能!把它留给遗留代码。模拟一个模拟返回一个模拟,返回一个模拟,(...),返回一些有意义的暗示违反德墨忒耳定律或模拟一个值对象(一个众所周知的反模式)。
- 如果上一点还不够,那么下一点,之后的几行,显然设置了一个很大的限制:
当无法模拟链中包含的任何返回类型的方法时(例如:是原始类或最终类),此功能将不起作用。这是因为 java 类型系统。
第二点意味着如果我尝试以这种方式模拟executeUpdate()
返回 an 的方法,int
它会引发异常。
when(entityManager.createQuery(anyString())
.setParameter(eq("param"), anyString())
.executeUpdate())
.thenReturn(1);
这样我就无法测试与entityManager
.
问题
- 我应该如何模拟电话
entityManager
?在我看来,我必须一个一个地模拟每种方法。 - 用错了
Answers.RETURNS_DEEP_STUBS
吗?如果没有,我该如何处理第二个例子?
解决方案
不要模拟 JPA API,只需使用适当的测试数据编写集成测试并针对真实数据执行真实查询以查看一切是否正常。像testcontainers这样的项目使上手变得非常容易。
推荐阅读
- javascript - 怎么去掉空的
使用 JavaScript 或 Cheerio 从字符串中标记标签?
- json - .map 没有返回值(不是函数)
- ruby - 有没有办法使用鞋子生成随机整数?
- c - C-问题:如何将主方法参数传递给方法的字符串变量?
- unity3d - 无法构建任何 apk
- linux - Jenkins 无法连接到 github repo
- java - 在测验中的最后一个问题之后转到 Android Studio 中的另一个活动
- javascript - 如何使用 React 和 Redux 更新数据库条目?
- matlab - 如何在 Matlab 中计算图像的直径?
- java - 如何在java中将三个数组转换为矩阵(二维数组)