単体テストで XML を検証する最良の方法は何でしょうか?
-
09-06-2019 - |
質問
私はクラスを持っています ToString
XML を生成するメソッド。単体テストを行って、有効な XML が生成されていることを確認したいと考えています。XML を検証するための DTD があります。
依存関係を避けるために単体テスト内に DTD を文字列として含めるべきか それとももっと賢い方法はあるのでしょうか?
解決
プログラムが通常の実行中に XML を DTD と照合して検証する場合は、プログラムが取得できる場所から DTD を取得する必要があります。
そうでなく、DTD が非常に短い (数行のみ) 場合は、コード内に文字列として保存してもおそらく問題ありません。
それ以外の場合は、それを外部ファイルに置き、単体テストでそのファイルから読み取るようにします。
他のヒント
使ったことがある XmlUnit 過去に使ってみて、便利だと感じました。
これは、XML をスキーマに対して検証したり、XML を文字列と比較したりするために使用できます。XML の解析ルールを理解できるほど賢いのです。たとえば、「<e1/>」が「<e1></e1>」と同等であることが認識されており、空白を無視するか含めるように構成できます。
単体テストで DTD を使用してその有効性をテストすることと、コンテンツが正しいかどうかをテストすることは別のことです。
DTD を使用して、生成された XML の有効性をチェックできます。これは、プログラム内で行う方法と同じように読み取るだけです。私は個人的には、これをインライン (文字列として) 含めません。アプリケーション コードと単体テストの間には常に依存関係が存在します。生成された XML が変更されると、DTD も変更されます。
正しいコンテンツをテストするには、次のようにします XMLユニット.
XMLUnit を使用して XML をアサートします。
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
Diff diff = new Diff(expectedDocument, obtainedDocument);
XMLAssert.assertXMLIdentical("xml invalid", diff, true);
生成された XML に変更される識別子 (id/uid 属性など) が含まれる可能性があるという事実に遭遇する可能性があります。これは次の方法で解決できます。 差分リスナー 生成された XML をアサートするとき。
このような DifferenceListener の実装例:
public class IgnoreVariableAttributesDifferenceListener implements DifferenceListener {
private final List<String> IGNORE_ATTRS;
private final boolean ignoreAttributeOrder;
public IgnoreVariableAttributesDifferenceListener(List<String> attributesToIgnore, boolean ignoreAttributeOrder) {
this.IGNORE_ATTRS = attributesToIgnore;
this.ignoreAttributeOrder = ignoreAttributeOrder;
}
@Override
public int differenceFound(Difference difference) {
// for attribute value differences, check for ignored attributes
if (difference.getId() == DifferenceConstants.ATTR_VALUE_ID) {
if (IGNORE_ATTRS.contains(difference.getControlNodeDetail().getNode().getNodeName())) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
}
// attribute order mismatch (optionally ignored)
else if (difference.getId() == DifferenceConstants.ATTR_SEQUENCE_ID && ignoreAttributeOrder) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
// attribute missing / not expected
else if (difference.getId() == DifferenceConstants.ATTR_NAME_NOT_FOUND_ID) {
if (IGNORE_ATTRS.contains(difference.getTestNodeDetail().getValue())) {
return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
}
return RETURN_ACCEPT_DIFFERENCE;
}
@Override
public void skippedComparison(Node control, Node test) {
// nothing to do
}
}
DifferenceListener を使用して:
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
Diff diff = new Diff(expectedDocument, obtainedDocument);
diff.overrideDifferenceListener(new IgnoreVariableAttributesDifferenceListener(Arrays.asList("id", "uid"), true));
XMLAssert.assertXMLIdentical("xml invalid", diff, true);