使用 Mockito 模拟 JPA CriteriaBuilder

发布于 2025-01-03 22:25:25 字数 2201 浏览 1 评论 0原文

我有一个特别令人讨厌的 JPA 查询 JMock check() 块,我想迁移到 Mockito

Mockery jMock = new Mockery();
final EntityManager fakeEntityManager = jMock.mock(EntityManager.class);
final CriteriaBuilder fakeCriteriaBuilder = jMock.mock(CriteriaBuilder.class);
final CriteriaQuery<String> fakeCriteriaQuery = jMock.mock(CriteriaQuery.class);
jMock.checking(new Expectations() {{
    oneOf(fakeEntityManager).getCriteriaBuilder(); will(returnValue(fakeCriteriaBuilder));
    oneOf(fakeCriteriaBuilder).createQuery(String.class); will(returnValue(fakeCriteriaQuery));
    oneOf(fakeCriteriaQuery).from(Archiveusergrouplicences.class);
    oneOf(fakeCriteriaQuery).select(with(any(Selection.class)));
    oneOf(fakeCriteriaBuilder).isNotNull(with(any(Expression.class)));
    oneOf(fakeCriteriaQuery).where(with(any(Expression.class)));
    oneOf(fakeEntityManager).createQuery(fakeCriteriaQuery);
    // Return an empty resultset
}});

正在测试的代码如下所示:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<String> criteria = builder.createQuery(String.class);

Root<Archiveusergrouplicences> institution = criteria.from(Archiveusergrouplicences.class);
criteria.select(institution.get(Archiveusergrouplicences_.usergroupid));    
criteria.where(builder.isNotNull(institution.get(Archiveusergrouplicences_.usergroupid)));

List<String> result = entityManager.createQuery(criteria).getResultList();

我发现 这个关于模拟构建器的问题,这在某种程度上解决了模拟的 CriteriaBuilder 部分;但我的主要问题是使用模拟对象作为另一个模拟的 .thenReturn() 值 - Mockito 似乎不允许这样做。例如,对于以下行:

CriteriaQuery<String> criteria = builder.createQuery(String.class);

我想返回模拟 CriteriaQuery 对象,如下所示:

CriteriaQuery<String> fakeCriteriaQuery = mock(CriteriaQuery.class, RETURNS_DEEP_STUBS);
when(entityManager.createQuery(anyString())).thenReturn(fakeCriteriaQuery);

这会引发语法错误:

OngoingStubbing 类型中的方法 thenReturn(Query) 不是 适用于参数 (CriteriaQuery)

我如何测试此代码,或改进它以使其更易于测试?

I have a particularly nasty JMock checking() block for a JPA query that I want to migrate to Mockito:

Mockery jMock = new Mockery();
final EntityManager fakeEntityManager = jMock.mock(EntityManager.class);
final CriteriaBuilder fakeCriteriaBuilder = jMock.mock(CriteriaBuilder.class);
final CriteriaQuery<String> fakeCriteriaQuery = jMock.mock(CriteriaQuery.class);
jMock.checking(new Expectations() {{
    oneOf(fakeEntityManager).getCriteriaBuilder(); will(returnValue(fakeCriteriaBuilder));
    oneOf(fakeCriteriaBuilder).createQuery(String.class); will(returnValue(fakeCriteriaQuery));
    oneOf(fakeCriteriaQuery).from(Archiveusergrouplicences.class);
    oneOf(fakeCriteriaQuery).select(with(any(Selection.class)));
    oneOf(fakeCriteriaBuilder).isNotNull(with(any(Expression.class)));
    oneOf(fakeCriteriaQuery).where(with(any(Expression.class)));
    oneOf(fakeEntityManager).createQuery(fakeCriteriaQuery);
    // Return an empty resultset
}});

The code being tested looks like this:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<String> criteria = builder.createQuery(String.class);

Root<Archiveusergrouplicences> institution = criteria.from(Archiveusergrouplicences.class);
criteria.select(institution.get(Archiveusergrouplicences_.usergroupid));    
criteria.where(builder.isNotNull(institution.get(Archiveusergrouplicences_.usergroupid)));

List<String> result = entityManager.createQuery(criteria).getResultList();

I've found this question on mocking builders, which goes some way to solving the CriteriaBuilder part of the mock; but my main problem is with using mocked objects as the .thenReturn() value of another mock - Mockito does not seem to allow that. For example, for the line:

CriteriaQuery<String> criteria = builder.createQuery(String.class);

I want to return the mock CriteriaQuery object, like this:

CriteriaQuery<String> fakeCriteriaQuery = mock(CriteriaQuery.class, RETURNS_DEEP_STUBS);
when(entityManager.createQuery(anyString())).thenReturn(fakeCriteriaQuery);

This throws a syntax error:

The method thenReturn(Query) in the type OngoingStubbing is not
applicable for the arguments (CriteriaQuery)

How might I go about testing this code, or improving it to make it more testable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白鸥掠海 2025-01-10 22:25:25

事实证明,您可以从其他模拟返回模拟 - 只要您设置正确的参数!我试图断言:

when(entityManager.createQuery(anyString())).thenReturn(fakeCriteriaQuery);

当我真正想要的是通过一个课程时:

when(fakeCriteriaBuilder.createQuery(String.class)).thenReturn(fakeCriteriaQuery);

错误是 Mockito 以神秘的方式告诉我,我已经搞砸了我的期望。

然而,我可能会考虑重写这个测试,而不是翻译最初编写的内容。正如一些人指出的那样;通常最好避免以这种方式模拟库,并且检查的条件相当模糊。

It turns out you can return mocks from other mocks - so long as you set the right arguments! I was attempting to assert:

when(entityManager.createQuery(anyString())).thenReturn(fakeCriteriaQuery);

When what I actually wanted was to pass in a Class:

when(fakeCriteriaBuilder.createQuery(String.class)).thenReturn(fakeCriteriaQuery);

The error was Mockito's cryptic way of telling me I had screwed up my expectation.

However, I may look into rewriting this test rather than translating what was originally written. As some have pointed out; it's often better to avoid mocking libraries in this way, and the condition being checked for is rather vague.

邮友 2025-01-10 22:25:25

就像你 jMock CriteriaQuery

final CriteriaQuery<String> fakeCriteriaQuery = jMock.mock(CriteriaQuery.class);

你也需要mockito CriteriaQuery

final CriteriaQuery<String> fakeCriteriaQuery = mock(CriteriaQuery.class);

Like you jMock CriteriaQuery

final CriteriaQuery<String> fakeCriteriaQuery = jMock.mock(CriteriaQuery.class);

You need to mockito CriteriaQuery too

final CriteriaQuery<String> fakeCriteriaQuery = mock(CriteriaQuery.class);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文