0

所以我有以下输入、预期输出和实际输出xml:

输入.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>

预期输出.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 设置进行比较:

我的测试.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();

当我运行上述输入并与 expected-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)]

我不明白为什么我的元素选择器不起作用,我是否使用不正确?我的目标是每当找到 TransmissionId 或 NotificationRq/RqUID 时,仅按名称将它们与预期的输出版本匹配,否则将名称和文本用于其他元素,因为这些元素包含唯一生成的 ID,这些 ID 会更改每次测试运行且无法预测(为了稍后创建更复杂的选择器,例如通过名称和属性比较 ProductRq,因为添加了命名空间)。有什么我遗漏的吗,我是否能够将 2 个 XPath 选择器组合在一起,而不是几个 when/then 行和默认情况?

注意:xml 是通过 xslt 转换的。PRoductRq 上的命名空间不在源文档中;复制源,将命名空间添加到 ProductRq,然后与一些元素删除/修改/添加一起发送以输出

4

1 回答 1

2

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如果他们有TransID任意内容的孩子,则匹配s。
  • NotificationRq如果它们具有RqUID任意内容,则匹配s。
  • 否则使用元素名称和嵌套文本

这不适合你的例子。查看您可能想要的 XML

  • 通过元素名称和嵌套文本匹配几乎所有内容(尽管从示例中元素名称就足够了)
  • 忽略s的TransId子级的嵌套文本Audit
  • 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.

这本身不足以忽略匹配TransIdRqUID元素的嵌套文本,它只会确保 XMLUnit 将选择您希望它使用的节点。对于嵌套文本,您需要一个DifferenceEvaluator.

鉴于您ElementSelectors.byNameAndText默认使用的是,您知道嵌套文本对于所有匹配节点都是相同的,除了您要忽略内容的两个特定元素。所以DifferenceEvaluator喜欢

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

应该管用。

于 2017-02-14T05:36:25.383 回答