2017-02-13 3 views
0

Так что я следующий ввод, ожидаемый результат и фактический вывод XML:XMLUnit: Ошибка с ElementSelectors.conditionalBuilder

Input.xml

<Request> 
    <EmailSubjectLine>Main Contact &amp; No Reported To</EmailSubjectLine> 
    <ProductRq> 
     <Signon> 
     <ClientDt>1/6/2017 11:25:45 AM</ClientDt> 
     <CustLangPref>en-US</CustLangPref> 
     </Signon> 
     <SvcRq> 
      <RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID> 
      <NotificationRq> 
       <TransactionRequestDt>2017-01-06</TransactionRequestDt> 
       <Currency>USD</Currency> 
      </NotificationRq> 
     </SvcRq> 
    </ProductRq> 
<!-- rest of input --> 
</Request> 

ожидаемой output.xml

<ProductRq xmlns="http://test.org/standards/intake"> 
    <Audit> 
     <TransID>Test</TransID> 
    </Audit> 
    <Signon> 
     <ClientDt>1/6/2017 11:25:45 AM</ClientDt> 
     <CustLangPref>en-US</CustLangPref> 
    </Signon> 
    <SvcRq> 
     <RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID> 
     <NotificationRq> 
      <RqUID>Test</RqUID> 
      <TransactionRequestDt>2017-01-06</TransactionRequestDt> 
      <Currency>USD</Currency> 
     </NotificationRq> 
    </SvcRq> 
    <!-- rest of expected-output --> 
</ProductRq> 

фактический-выход.xml

<ProductRq xmlns="http://test.org/standards/intake"> 
    <Audit> 
     <TransID>123534Abwe-asdcv-1258qw-asd</TransID> 
    </Audit> 
    <Signon> 
     <ClientDt>1/6/2017 11:25:45 AM</ClientDt> 
     <CustLangPref>en-US</CustLangPref> 
    </Signon> 
    <SvcRq> 
     <RqUID>xxxxxxxx-2802-xxxx-xxxx-bf8361xxxxxx</RqUID> 
     <NotificationRq> 
      <RqUID>CG-17Dawe-12354-Hw35Sf</RqUID> 
      <TransactionRequestDt>2017-01-06</TransactionRequestDt> 
      <Currency>USD</Currency> 
     </NotificationRq> 
    </SvcRq> 
    <!-- rest of actual-output --> 
</ProductRq> 

Я сравнивая их со следующим Diff настройки:

MyTest.java

 Diff diff = DiffBuilder 
       .compare(xmlExpectedOutput) 
       .withTest(xmlOutput) 
       .normalizeWhitespace() 
       .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder() 
         .whenElementIsNamed("Audit") 
         .thenUse(ElementSelectors.byXPath("./TransID", ElementSelectors.byName)) 
         .whenElementIsNamed("NotificationRq") 
         .thenUse(ElementSelectors.byXPath("./RqUID", ElementSelectors.byName)) 
         .elseUse(ElementSelectors.byNameAndText) 
         .build() 
         )) 
       .checkForSimilar() 
       .build(); 

я получаю следующие различия, когда я запускаю выше вход и сравнить с ожидаемым -output.xml:

[Expected child '{http://test.org/standards/intake}RqUID' but was 'null' - comparing <RqUID...> at /ProductRq[1]/SvcRq[1]/NotificationRq[1]/RqUID[1] to <NULL> (DIFFERENT), Expected child 'null' but was '{http://test.org/standards/intake}RqUID' - comparing <NULL> to <RqUID...> at /ProductRq[1]/SvcRq[1]/NotificationRq[1]/RqUID[1] (DIFFERENT)]

Я не понимаю, почему мой переключатель Element не работал, я использую его неправильно? Моя цель - всякий раз, когда обнаружены TransmissionId или NotificationRq/RqUID, чтобы соответствовать им с ожидаемыми выходными версиями только по имени, иначе используйте имя и текст для других элементов, поскольку эти элементы содержат уникальные генерируемые идентификаторы, которые изменяют каждый тестовый прогон и не могут быть предсказаны (с целью создания более сложного селектора позже, например, для сравнения ProductRq через имя и атрибут, поскольку к нему добавляется пространство имен). Есть ли что-то, что мне не хватает, и могу ли я объединить 2 селектора XPath вместе, а не несколько, когда/then линии и случай по умолчанию?

Примечание: xml преобразуется через xslt. Пространство имен на PRoductRq отсутствует в исходном документе; источник копируются, пространство имен добавляются к ProductRq, а затем отправлены на выход наряду с некоторыми элементом абсорбции/модификации/дополнениями

ответ

1

XMLUnit говорит RqUID элементов внутри NotificationRq не будут соответствовать и, конечно, они различны.

.whenElementIsNamed("NotificationRq") 
.thenUse(ElementSelectors.byXPath("./RqUID", ElementSelectors.byName)) 

означает: когда XMLUnit пытается найти партнера для NotificationRq элемента, то он должен искать для NotificationRq, который имеет RqUID ребенка - и использовать только RqUID элемент.

Он не устанавливает никаких правил для любого другого элемента, в частности RqUID. Для RqUID элементов правило по умолчанию применяется и

.elseUse(ElementSelectors.byNameAndText) 

говорит: XMLUnit принимает только два элемента, как пар, если их имена и вложенная текст матча. Это не относится к элементам RqUID.

Ваш весь ElementSelector говорит

  • матч Audit s, если они имеют TransID детей произвольного содержания.
  • соответствует NotificationRq с, если у них есть RqUID произвольного содержания.
  • использовать имя элемента и вложенный текст иначе

который не соответствует вашему примеру. Глядя на ваш XML вы, вероятно, хотели

  • матч почти весь по имени элемента и вложенным текст (хотя на примере имя элемента будет достаточно)
  • игнорировать вложенный текст TransId детей Audit s
  • игнорировать вложен текст RqUID детей NotificationRq

Там нет встроенных в предикат «элемента с именем foo, если он является потомком элемента с именем bar», это может быть что-то вроде

Predicate<Element> transIdInAudit = e -> { 
    if (e == null || e.getParentNode() == null) { 
     return false; 
    } 
    return "TransID".equals(e.getLocalName()) && "Audit".equals(e.getParentNode().getLocalName()); 
}; 

, которые вы, вероятно, хотите сделать обобщению :-)

С, что вы будете использовать

.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder() 
    .when(transIdInAudit) 
    .thenUse(ElementSelectors.byName) 
    .when(rqUIDInNotificationRq) // similar to transIdInAudit 
    .thenUse(ElementSelectors.byName) 
    .elseUse(ElementSelectors.byNameAndText) 
    .build()) 

Может быть, вы действительно хотите, чтобы соответствовать SvcRq, если они имеют соответствие RqUID, может быть, нет. Если это так, вы бы использовали структуру, которую используете в настоящее время для NotificationRq.

Этого само по себе недостаточно, чтобы игнорировать вложенный текст совпадающих элементов TransId и RqUID, это гарантирует, что XMLUnit будет выбирать узлы, которые вы хотите использовать. Для вложенного текста вам понадобится DifferenceEvaluator.

Учитывая, что вы используете ElementSelectors.byNameAndText по умолчанию, вы знаете, что вложенные тексты одинаковы для всех совпадающих узлов, за исключением двух конкретных элементов, в которых вы хотите игнорировать содержимое. Таким образом, DifferenceEvaluator, как

DifferenceEvaluators.chain(DifferenceEvaluators.Default, 
    DifferenceEvaluators.downgradeDifferencesToEqual(ComparisonType.TEXT_VALUE)) 

должно работать.

+0

отличное объяснение, я думаю, что я неправильно интерпретировал селектор элементов byXPath, я думал, что это было по строкам, если этот элемент назван этим, а затем сопоставить этот ребенок с предоставленным селектором, а не то, что он должен использовать только RqUID с по умолчанию. В конце концов, я пришел к решению, выполнив 2 DifferenceEvaluators, но это намного чище – jbailie1991