代码之家  ›  专栏  ›  技术社区  ›  Thorbjørn Ravn Andersen

测试SpringBootRestTemplate客户机的JSON映射

  •  2
  • Thorbjørn Ravn Andersen  · 技术社区  · 6 年前

    我有一个超出我控制范围的RESTAPI(由另一个遥远的团队提供),我需要从一个Spring引导应用程序中使用它。

    目前我想为此编写一个测试 请求 (不是响应)我的resttemplate调用产生的结果与远程端的预期完全对应。我有一个示例JSON片段,我想从我的代码中复制它——给定与示例中相同的参数,我应该在请求主体中得到一个等效的JSON片段,然后我想分析它以确保这一点。

    到目前为止,我的想法是让resttemplate使用我控制的服务器,然后捕获JSON请求。显然 MockRestServiceServer 是个不错的选择。

    这是正确的方法吗?如何配置MockRestServiceServer以允许我执行此操作?

    3 回复  |  直到 6 年前
        1
  •  3
  •   Thorbjørn Ravn Andersen    6 年前

    如果您只对验证JSON映射感兴趣,那么可以始终使用Jackson的 ObjectMapper 直接使用类似的库来验证对象结构是否匹配 JSONassert 验证序列化字符串是否与预期结果匹配。例如:

    @Autowired
    private ObjectMapper objectMapper;
    private Resource expectedResult = new ClassPathResource("expected.json");
    
    @Test
    public void jsonMatches() {
        Foo requestBody = new Foo();
        String json = objectMapper.writeValueAsString(requestBody);
        String expectedJson = Files
            .lines(expectedResult.getFile())
            .collect(Collectors.joining());
        JSONAssert.assertEquals(expectedJson, json, JSONCompareMode.LENIENT);
    }
    

    此测试纯粹使用 对象映射器 为了验证JSON映射和其他任何东西,您甚至可以这样做,而不必在测试中启动Spring引导(这可能更快)。这样做的缺点是,如果您使用的框架与Jackson不同,或者 RestTemplate 更改其实现,使此测试可能过时。


    或者,如果您有兴趣验证完整的请求是否匹配(URL、请求方法、请求正文等),可以使用 MockRestServiceServer 正如你提到的。这可以通过添加 @SpringBootTest 测试注释,自动布线 REST模板 以及调用的服务 REST模板 例如:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FooServiceTests {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private FooService fooService; // Your service
    
        private MockRestServiceServer server;
    
        @Before
        public void setUp() {
            server = MockRestServiceServer.bindTo(restTemplate).build();
        }
    }
    

    然后,您可以使用以下方法设置测试:

    @Test
    public void postUsesRestTemplate() throws IOException, URISyntaxException {
        Path resource = Paths.get(getClass().getClassLoader().getResource("expected-foo.json").toURI());
        String expectedJson = Files.lines(resource).collect(Collectors.joining());
        server.expect(once(), requestTo("http://example.org/api/foo"))
            .andExpect(method(HttpMethod.POST))
            .andExpect(MockRestRequestMatchers.content().json(expectedJson))
            .andRespond(withSuccess());
        // Invoke your service here
        fooService.post();
        server.verify();
    }
    
        2
  •  1
  •   Laksitha Ranasingha    6 年前

    根据文档,您可以在mock上使用JSON路径匹配请求。例如;

    RestTemplate restTemplate = new RestTemplate()
     MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
    
    server.expect(ExpectedCount.once(), requestTo(path))
                    .andExpect(method(HttpMethod.POST))
                    .andExpect(jsonPath("$", hasSize(1)))
                    .andExpect(jsonPath("$[0].someField").value("some value"))
    

    注意:我还没有测试过这个。

    但我已经实现了你要找的用铁丝网模拟很多次。这又是一个比 MockRestServiceServer . 我为什么这么说?

    • 广泛采用和支持
    • 更优雅、更广泛的请求和响应匹配
    • 高度可配置
    • 回放
    • 可配置的安全性/身份验证
    • 你甚至可以把这个搞乱

    看一看 http://wiremock.org/docs/request-matching/

        3
  •  1
  •   Adriaan Koster    6 年前

    我认为您使用存根服务器的方法(您可以使用 WireMock 如果您想手动检查一次,就可以了。

    或者您可以添加 request logger 记录每个请求的resttemplate。这将使在出现问题时更容易检查发送的请求是否正确。