| 2021-02-07
下面的测试用例将对 CloudService 的服务调用进行模拟替代( mocks )。 这个测试用例真的能为我们提供足够的信心吗,它让你相信:这个服务调用是可以正确工作的了么?
@Test public void uploadFileToCloudStorage() {
when(mockCloudService.write(
WriteRequest.newBuilder().setUserId(“testuser”).setFileType(“plain/text”)...))
.thenReturn(WriteResponse.newBuilder().setUploadId(“uploadId”).build());
CloudUploader cloudUploader = new CloudUploader(mockCloudService);
Uri uri = cloudUploader.uploadFile(new File(“/path/to/foo.txt”));
// The uploaded file URI contains the user ID, file type, and upload ID. (Or does it?)
assertThat(uri).isEqualTo(new Uri(“/testuser/text/uploadId.txt”));
这个测试中,很多地方都可能出错, 尤其是当服务契约变得复杂时。例如,plain/text 可能不是一个有效的文件类型,而你验证上传文件的 URI 是正确的。
**如果被测代码依赖于某个服务的契约,建议对这个服务调用进行检查,**而不是对其进行模拟替代( mocking it out )。这让你对能够正确使用这个外部服务更有信心:
@Test public void uploadFileToCloudStorage() {
CloudUploader cloudUploader = new CloudUploader(cloudService);
Uri uri = cloudUploader.uploadFile("/path/to/foo.txt");
assertThat(cloudService.retrieveFile(uri)).isEqualTo(readContent("/path/to/foo.txt"));
你如何检查这个服务调用呢?
- 使用一个 fake 服务。一个 fack 对象是某个真实服务的快速且轻量级的实现,它的行为就象它模仿的真实服务一样。一个fake服务通常是由服务的提供者负责维护;除非你能保证Fake服务的行为与真实实现一直保持一致,否则不要自己创建自己的fake服务。关于更多的Fake服务,参见 fake .
- 使用一个封闭服务器( hermetic )。这是一个真实的服务,它是由测试用例在其运行的同一台机器上启动的。使用密闭服务器的缺点是启动它并与其交互会让测试运行比较慢。关于更多的密闭服务器,参见 使用封闭服务进行端到端测试.
假如很多服务都没有自己的 fake 服务或者密闭服务器,模拟器(mock)可有是你的唯一选择了。但是,如果你的测试并没有使用真正的调用契约来请求真正的服务,那你要格外小心,确保那个测试所调用的真正服务是正常工作的,例如可以通过一个全面的端到端的测试用例,或者求助于手工测试(但这可能效率低,而且不容易扩展规模)。
发表时间:November 27, 2018
原文作者:Ben Yu
原文链接:Testing on the Toilet: Exercise Service Call Contracts in Tests