添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
61
41

More than 3 years have passed since last update.

JSONPath 使い方まとめ

Last updated at Posted at 2020-03-26

先輩「MockMvcでJSONPathを使おうと思ってて…」

@takkii1010 「…?」

となったので、以下を簡単にまとめたい。

  • JSONPathとは何者か
  • JSONPathの構文
  • MockMvcでの使い方
  • 1. JSONPathとは何者か

    Data may be interactively found and extracted out of JSON structures on the client without special scripting.
    JSONPath expressions always refer to a JSON structure in the same way as XPath expression are used in combination with an XML document.

  • XPath for JSON
  • 特別なスクリプトを書かずとも、JSONを双方向に検出&抽出できるライブラリ
  • XPathがXMLを参照するのと同様に、JSONPathは常にJSONを参照するようになっている
  • XPathとは何者か
  • min() , max() , avg() , stddev() , length() , sum() があります。
    length() $.phoneNumbers.length とあまり深く考えずに使えますが、他の関数が少し厄介。

    こんな感じのJSONの場合…

    "id" : 1 , "name" : "スクエ…" , "products" : [ "name" : "FINAL FANTASY VII" , "price" : 1572 "name" : "FINAL FANTASY X" , "price" : 8800 "name" : "FINAL FANTASY XV" , "price" : 8800

    一度取り出してから、処理を行う必要があるらしい。
    https://oboe2uran.hatenablog.com/entry/2018/05/06/131634

    MockMvcを使う場合は以下で動きました。

            val jsonObject = mockMvc.perform(get("/gameCompanies/1"))
                    .andExpect(status().isOk())
                    .andReturn().response.contentAsString
            val priceList: List<Int> = JsonPath.read( jsonObject, "\$.products[*].price")
            val min: Int = JsonPath.read(priceList, "\$.min()")
            val max: Int = JsonPath.read(priceList, "\$.max()")
            val sum: Int = JsonPath.read(priceList, "\$.sum()")
            val stddev: Int = JsonPath.read(priceList, "\$.stddev()")
            assertThat(min).isEqualTo(1572)
            assertThat(max).isEqualTo(8800)
            assertThat(sum).isEqualTo(19172)
            assertThat(stddev).isEqualTo(3407)
    

    他にこちらにも例が載ってます

    3. MockMvcでの使い方
    @RunWith(SpringRunner::class)
    @WebMvcTest(GameCompanyController::class)
    class GameCompanyControllerTest {
        @Autowired
        lateinit var mockMvc: MockMvc
        @MockBean
        lateinit var gameCompanyRepository: GameCompanyRepositoryInterface
        @Test
        fun getGameCompanyTest() {
            val expectedGameCompany = GameCompany(
                    id = 1L,
                    name = "スクエ…",
                    products = listOf(
                            Product("FINAL FANTASY VII", BigDecimal(1572)),
                            Product("FINAL FANTASY X", BigDecimal(8800)),
                            Product("FINAL FANTASY XV", BigDecimal(8800))
            `when`(gameCompanyRepository.fetchGameCompany(any())).thenReturn(expectedGameCompany)
            mockMvc.perform(get("/gameCompanies/1")
                    .contentType(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("\$.id").value(1))
                    .andExpect(jsonPath("\$.name").value("スクエ…"))
                    .andExpect(jsonPath("\$.products[0].name").value("FINAL FANTASY VII"))
                    .andExpect(jsonPath("\$.products[0].price").value(1572))
                    .andExpect(jsonPath("\$.products[1].name").value("FINAL FANTASY X"))
                    .andExpect(jsonPath("\$.products[1].price").value(8800))
                    .andExpect(jsonPath("\$.products[2].name").value("FINAL FANTASY XV"))
                    .andExpect(jsonPath("\$.products[2].price").value(8800))
    

    Kotlinの indices 使うとこんな感じ。

    mockMvc.perform(get("/gameCompanies/1") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(expectedGameCompany.products) private fun ResultActions.andExpect(products: List<Product>): ResultActions { for (index in products.indices) { andExpect(jsonPath("\$.products[$index].name").value(products[index].name)) .andExpect(jsonPath("\$.products[$index].price").value(products[index].price)) return this

    他にも、 Matchers のisを使用しても動きます。

            mockMvc.perform(get("/gameCompanies/1")
                    .contentType(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("\$.id", `is`(1)))
    

    ただ、少し古い書き方のようなので、 value で書くのが良さそう。

    参考にしたサイト一覧

    https://goessner.net/articles/JsonPath/
    https://www.techscore.com/tech/XML/XPath/XPath1/xpath01.html/
    https://github.com/json-path/JsonPath
    http://oboe2uran.hatenablog.com/entry/2018/05/06/131634

    61
    41
    2

    Register as a new user and use Qiita more conveniently

    1. You get articles that match your needs
    2. You can efficiently read back useful information
    3. You can use dark theme
    What you can do with signing up
    61
    41