使用 Rest-Assured 提取嵌套的 POJO 对象

Extracting Nested POJO Object with Rest-Assured

我正在使用 rest-assured 及其 Kotlin 扩展编写一些测试来测试一些简单的 Spring MVC 端点。我正在尝试了解如何提取值。

一个端点returns一个BookDetailsView POJO,另一个returns一个Page<BookDetailsView>(其中Page是Spring提供的接口用于分页)。

BookDetailsView 是一个非常简单的 Kotlin 数据 class,只有一个字段:

data class BookDetailsView(val id: UUID)

对于单个对象端点,我有:

    @Test
    fun `single object`() {
        val details = BookDetailsView(UUID.randomUUID())

        whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
        val result: BookDetailsView = Given {
            mockMvc(mockMvc)
        } When {
            get("/book_details/${details.id}")
        } Then {
            statusCode(HttpStatus.SC_OK)
        } Extract {
            `as`(BookDetailsView::class.java)
        }
        assertEquals(details.id, result.id)
    }

这按预期工作,但尝试对 Page<BookDetailsView> 应用相同的技术会遇到各种解析挑战,因为 Page 是一个接口,甚至尝试使用 PageImpl 也不是'完全简单。最后,我什至不关心 Page 对象,我只关心它里面嵌套的 POJO 列表。

我已经尝试了各种排列,例如下面的代码,只抓住了我关心的部分:

    @Test
    fun `extract nested`() {
        val page = PageImpl(listOf(
            BookDetailsView(UUID.randomUUID())
        ))
        whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)

        val response = Given {
            mockMvc(mockMvc)
        } When {
            get("/book_details")
        } Then {
            statusCode(HttpStatus.SC_OK)
            body("content.size()", `is`(1))
            body("content[0].id", equalTo(page.first().id.toString()))
        } Extract {
            path<List<BookDetailsView>>("content")
        }
        println(response[0].javaClass)
    }

最终println吐出class java.util.LinkedHashMap。相反,如果我尝试实际使用该对象,我会得到 class java.util.LinkedHashMap cannot be cast to class BookDetailsView。有很多与此相关的问题和答案,我知道这最终是底层 JSON 解析器不知道该怎么做的问题,但我不清楚:

  1. 为什么“简单”案例解析没有问题?
  2. 传递给 path() 函数的类型参数不应该告诉它使用什么类型吗?
  3. 需要配置什么才能使第二种情况起作用,或者
  4. 是否有其他更有意义的获取嵌套对象的方法?

深入研究一下代码,似乎这两种情况实际上可能使用了不同的json parsers/configurations(前者似乎坚持放心的JSON解析,而后者最终出现在 JsonPath 中?)

我不知道科特林,但事情是这样的:

  • path() 不知道列表中的元素,因此默认情况下它将是 LinkedHashMap 而不是 BookDetailsView.class

  • 为了克服它,你可以为此提供 TypeReference。

java 例子

List<BookDetailsView> response = ....then()
                .extract().jsonPath()
                .getObject("content", new TypeRef<List<BookDetailsView>>() {});

科特林示例

@Test
fun `extract nested`() {
    var response = RestAssured.given().get("http://localhost:8000/req1")
            .then()
            .extract()
            .jsonPath()
            .getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});

    println(response)
    //[{id=1}, {id=2}]
}