我是java单元测试的新手;我有一个使用hibernate与mysql数据库交互的应用程序。
我有很多用 createQuery()
方法,也带有参数,如以下参数:
return this.entityManager.createQuery("from MyEntity m where param = :param", MyEntity.class)
.setParameter("param", param)
.getSingleResult();
我想避免嘲笑所有后续的电话会议 entityManager
对象,因为有时我会使用5个以上的参数进行查询,而模拟每个调用似乎不是那么方便。
同样的概念也可以应用于生成器对象。
编辑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;
一切如期。我可以模仿所有的电话链。但是
引用mockito.returns\u deep\u stubs的javadoc:
警告:对于常规的干净代码,应该很少需要此功能!留给遗留代码。mocking a mock返回一个mock,返回一个mock,(…),返回一些有意义的提示,表示违反了demeter定律,或者模仿了一个值对象(一个众所周知的反模式)。
如果上一点还不够,下一点,后面的几行,显然设置了很大的限制:
当链中包含的任何返回类型的方法都无法模拟时(例如:是原语或final类),此功能将不起作用。这是因为java类型的系统。
第二点意味着如果我试图用这种方式来模拟 executeUpdate()
,返回 int
,它引发了一个异常。
when(entityManager.createQuery(anyString())
.setParameter(eq("param"), anyString())
.executeUpdate())
.thenReturn(1);
这样我就不能测试和 entityManager
.
问题
我该如何嘲笑电话 entityManager
? 在我看来,我不可能一个一个地嘲笑每一种方法。
用错了吗 Answers.RETURNS_DEEP_STUBS
? 如果没有,我如何处理第二个例子?
1条答案
按热度按时间tct7dpnv1#
不要模仿jpaapi,只要用适当的测试数据编写集成测试,并对实际数据执行真正的查询,看看是否一切正常。像testcontainers这样的项目使它非常容易启动。