java - 如何验证具有特定参数的流畅接口模拟链
问题描述
在这被标记为重复之前,我已经浏览了我能找到的所有关于 SO 的主题,但我没有看到任何接近我想要实现的目标。
我正在为几个所谓的“流畅”接口编写单元测试,并且在验证方法调用链而又不会使其过于复杂和不可读的情况下遇到困难。也许,我以为我错过了一些东西,我只是想重新发明轮子。我该怎么做呢?
拥有一个模拟对象MyQuery mockedQuery
,我想实现以下目标:
MyQuery nameQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(nameQueryMock).when(mockedQuery)
.name("SPECIFIC NAME");
MyQuery addressQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(addressQueryMock).when(nameQueryMock)
.address("SPECIFIC ADDRESS");
Mockito.doReturn(JOHN_QUERY_RESULT).when(addressQueryMock)
.singleResult();
我希望做的更像是:
Mockito.when(mockedQuery.name("SPECIFIC NAME").address("SPECIFIC ADDRESS").singleResult()).thenReturn(JOHN_QUERY_RESULT);
但我发现这不是它的工作原理。我尝试使用 Mockito 提供的答案(RETURNS_DEEP_STUBS
这是我尝试过的事情之一),但我发现它仅适用于文档中指出的链的最后一个方法调用。在我的情况下,我JOHN_QUERY_RESULT
只需要在两个name()
方法都通过“特定名称”并address()
通过“特定地址”时返回。
我希望能够以更简洁的方式实现这一点,因为我的链包含更多方法,并且采用第一种方法会使我的测试重载,其中包含很多我希望避免的代码。 我在这里想念什么?
更新:
一些背景知识:有MyService
一个方法提供了一个createQuery()
返回新实例的方法MyQuery
。该服务(MyService
)用于我要测试的类中,该类做了一些工作,但它利用(那些)查询来检索有关它必须做的事情的信息。因此,在测试类中模拟和ing 它,也使用模拟将允许我测试行为本身,消除 的内部实现,只需能够指定特定查询搜索的返回值。MyService
Inject
MyQuery
MyQuery
解决方案
根据您的背景信息,我提出了以下示例:(
因此这可能与您的实际情况完全不同)
假设您的 TestClass 有这样的方法
public String someMethod(String name, String address) {
return service.createQuery().name(name).address(address).singleResult();
}
并且对它的测试看起来像这样:
@InjectMocks
TestClass testClass;
@Mock
MyService service;
@Test
public void test() {
MyQuery query = Mockito.mock(service);
when(service.createQuery()).thenReturn(query);
Mockito.when(mockedQuery.name("SPECIFIC NAME")
.address("SPECIFIC ADDRESS")
.singleResult())
.thenReturn("JOHN_QUERY_RESULT");
Assert.assertEquals("JOHN_QUERY_RESULT", testClass.someMethod("SPECIFIC NAME", "SPECIFIC ADDRESS"));
}
就我而言,仅当 name() 方法通过“特定名称”并且 address() 都通过“特定地址”时,我才需要返回 JOHN_QUERY_RESULT。
那部分已经被测试覆盖了,只是因为如果模拟不匹配你会得到一个NullPointerException
代替。
此外,这听起来像是与 的 UnitTest 无关的东西TestClass
,但应该与MyQuery
.
但是,让我们看一下测试。我们可以看到,测试的每一行都包含一个基于 a 的操作mock
。
我们通过该测试取得了什么成果?我们测试了TestClass
吗?
不,我们可以直接模拟整个TestClass
结果并直接返回结果。嘲笑TestClass
是不好的。
所以我的回答是:没什么。
我们已经验证了 mockito 做了应该做的事情,并且链接方法调用有效,但这超出了良好测试的范围。
我们可以做些什么来改善这一点?
我想说这样的测试对于 UnitTest 来说并不是真正的,更不用说模拟了,相反我们应该专注于集成测试。
如果MyQuery#singleResult
有一些 3rd 方交互,例如与数据库,那么这是可以模拟的。
但是最后我们仍然需要另一个集成测试来进行数据库交互。在那种情况下,我们最好限制自己只测试一些Exceptions
通常难以重现的东西。
推荐阅读
- docker - Feign.Builder“目标值必须是绝对”错误:如何使用绝对url调用docker容器?
- java - 重构方法以使用泛型进行反序列化
- android - 如何在 Firestore android 中添加多个回调?
- docker - 错误:提供的“html”报告器不存在
- r - 在绘图线图上添加标签
- google-cast - 自定义接收器中专辑艺术图像的奇怪渲染
- regex - Perl 中的开始和结束
- c# - C# ListBox 项自动更改颜色
- python - 我需要帮助将图像和音频剪辑组合成 1 个视频
- php - 我使用“将联系表格 7 数据保存到自定义数据库而不是 wordpress 数据库方法,并且文件上传不再保存到目录