MockHttpServletResponse: проверка содержимого xml

Я тестирую контроллер, используя MockMvc. Вот как выглядит ответ:

MockHttpServletResponse:
              Status = 200
       Error message = null
             Headers = {Content-Type=[text/xml]}
        Content type = text/xml
                Body = <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:diagnosisCode xmlns:ns2="http://schemas.mycompany.co.za/health" effectiveStartDate="2014-03-05T00:00:00+02:00" effectiveEndDate="2014-03-05T23:59:59.999+02:00" diagnosisId="1"><diagnosisCodeId><codingSchemaCode>irrelevant schema</codingSchemaCode><diagnosisCode>irrelevant code</diagnosisCode></diagnosisCodeId></ns2:diagnosisCode>
       Forwarded URL = null
      Redirected URL = null
             Cookies = []

Красиво напечатанная версия строки Body:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:diagnosisCode xmlns:ns2="http://schemas.mycompany.co.za/health" effectiveStartDate="2014-03-05T00:00:00+02:00" effectiveEndDate="2014-03-05T23:59:59.999+02:00" diagnosisId="1">
    <diagnosisCodeId>
        <codingSchemaCode>irrelevant schema</codingSchemaCode>
        <diagnosisCode>irrelevant code</diagnosisCode>
    </diagnosisCodeId>
</ns2:diagnosisCode>

Звонок на MockMvc выглядит так

mockMvc.perform(
        get("/diagnostic/diagnosisCodes/{schema}/{code}", IRRELEVANT_SCHEMA, IRRELEVANT_CODE).accept(MediaType.TEXT_XML))
        .andDo(print())
        .andExpect(content().contentType(MediaType.TEXT_XML))
        .andExpect(status().isOk())
        .andExpect(xpath("diagnosisCodeId/diagnosisCode").string(IRRELEVANT_CODE))
        .andExpect(xpath("diagnosisCodeId/codingSchemaCode").string(IRRELEVANT_SCHEMA));

Я почти уверен, что неправильно понимаю, как я должен использовать здесь XPath, но почему это утверждение не работает? Каким должно быть мое ожидание?

java.lang.AssertionError: XPath diagnosisCode expected:<irrelevant code> but was:<>

person Niel de Wet    schedule 05.03.2014    source источник
comment
Можете ли вы добавить свой исходный XML к вопросу и что вы ожидаете выбрать с помощью XPath?   -  person helderdarocha    schedule 05.03.2014


Ответы (2)


Я не совсем уверен, что такое контекст XPath (или это узел документа), но я вижу две возможные проблемы и предполагаю, что обе применимы:

  • Вы пытаетесь сопоставить < diagnosisCodeId/> элементов, которые являются корневыми элементами. Их нет, но они дети <diagnosisCode>. Либо включите шаг оси для корневого узла (вероятно, лучший способ), либо используйте шаг оси descendant-or-self // перед запросом.

    /diagnosisCode/diagnosisCodeId/diagnosisCode
    //diagnosisCodeId/diagnosisCode
    
  • В документе используются пространства имен (для корневого элемента). В дополнение к проблеме с корневым элементом, описанной выше, либо зарегистрируйте это пространство имен (лучшее решение, но я не знаю, как это сделать в Spring MVC), либо проигнорируйте его, используя следующий обходной путь:

    /*[local-name() = 'diagnosisCode']/diagnosisCodeId/diagnosisCode
    

    Что сначала соответствует всем дочерним узлам, но затем ограничивается теми, у которых есть соответствующее имя элемента (игнорируя пространства имен).

    Добавляя поддержку XPath 2.0 (например, включив Saxon в качестве библиотеки), вы также можете использовать сопоставление пространств имен с подстановочными знаками:

    /*:diagnosisCode/diagnosisCodeId/diagnosisCode
    

    Если вы зарегистрируете URI пространства имен http://schemas.mycompany.co.za/health как ns2, запрос будет выглядеть так:

    /ns2:diagnosisCode/diagnosisCodeId/diagnosisCode
    
person Jens Erat    schedule 05.03.2014
comment
Существует также более простая формулировка /*[local-name() = 'diagnosisCode']/*[local-name() = 'diagnosisCodeId']/*[local-name() = 'diagnosisCode'], которая представляет собой /*:diagnosisCode/*:diagnosisCodeId/*:diagnosisCode. - person adamretter; 06.03.2014
comment
Поддерживает ли Spring MVC XPath 2.0? После этого ответа кажется, что я добавлю это к ответу. - person Jens Erat; 06.03.2014
comment
@adamretter К сожалению, у меня это не работает. - person Niel de Wet; 06.03.2014
comment
@JensErat Теперь у меня все работает. Единственное, префикс пространства имен должен быть только у корневого элемента. Пожалуйста, отредактируйте свой ответ. - person Niel de Wet; 06.03.2014
comment
Вы правы, я упустил из виду, что пространства имен использовались только в элементе, а пространства имен по умолчанию не применялись. В следующий раз лучше также добавить какую-нибудь красиво напечатанную версию XML, это упростит задачу. - person Jens Erat; 06.03.2014

Существует перегрузка для xpath, которая принимает Map<String, String> пространств имен:

Map<String, String> ns = Map.of("ns2", "http://schemas.mycompany.co.za/health");
mockMvc.perform(get("/diagnostic/diagnosisCodes/{schema}/{code}", IRRELEVANT_SCHEMA, IRRELEVANT_CODE)
        .accept(MediaType.TEXT_XML))
        .andExpect(xpath("ns2:diagnosisCodeId/diagnosisCode", ns).string(IRRELEVANT_CODE))
        .andExpect(xpath("ns2:diagnosisCodeId/codingSchemaCode", ns).string(IRRELEVANT_SCHEMA));
person OrangeDog    schedule 10.10.2019