Xmlをテストするために人々が推奨する単体テスト戦略は正しく生成されています。
私の現在のテストは、次のような原始的なもののようです。
[Test]
public void pseudo_test()
{
XmlDocument myDOC = new XmlDocument();
mydoc = _task.MyMethodToMakeXMLDoc();
Assert.AreEqual(myDoc.OuterXML(),"big string of XML")
}
まず、ほとんどの人が言っているように、XMLにスキーマが定義されている場合は、XMLを検証します。 (ない場合は、定義します。)
ただし、ドキュメントに対してXPathクエリを実行することで、テストよりもはるかに詳細なテストを作成できます。例:
string xml="Your xml string here" ;
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
path = "/doc/element1[@id='key1']/element2[. = 'value2']";
Assert.IsTrue(doc.SelectSingleNode(path) != null);
これにより、ドキュメントがセマンティック的に有効であるかどうかだけでなく、ドキュメントを生成するメソッドが期待する値をドキュメントに入力しているかどうかをテストできます。
XMLUnit が役立つ場合があります。
Fluent Assertions は、流暢で読みやすいスタイルでテストアサーションを表現するための優れたライブラリです。これは、すべての主要なユニットテストフレームワークで機能します。
また、いくつかの便利なXML機能(すべて例から抜粋 ここ )があります。例:
xElementA.Should().Be(xElementB);
xDocument.Should().HaveRoot("configuration");
xDocument.Should().HaveElement("settings");
xElement.Should().HaveAttribute("age", "36");
xElement.Should().HaveElement("address");
xAttribute.Should().HaveValue("Amsterdam");
これは、元の質問で指定されたXmlDocumentオブジェクトではなくLINQ-To-XMLで機能することに注意してください。しかし、個人的には、最近、最初の選択肢としてLINQ-To-XMLを使用していることがわかりました。
また、ニーズに合わせてXMLアサーションをさらに追加したい場合は、非常に簡単に拡張できます。
もう1つの可能性は、XmlReaderを使用して、エラー数が0より大きいかどうかを確認することです。次のようなものです。
void CheckXml()
{
string _xmlFile = "this.xml";
string _xsdFile = "schema.xsd";
StringCollection _xmlErrors = new StringCollection();
XmlReader reader = null;
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationEventHandler += new ValidationEventHandler(this.ValidationEventHandler);
settings.ValidationType = ValidationType.Schema;
settings.IgnoreComments = chkIgnoreComments.Checked;
settings.IgnoreProcessingInstructions = chkIgnoreProcessingInstructions.Checked;
settings.IgnoreWhitespace = chkIgnoreWhiteSpace.Checked;
settings.Schemas.Add(null, XmlReader.Create(_xsdFile));
reader = XmlReader.Create(_xmlFile, settings);
while (reader.Read())
{
}
reader.Close();
Assert.AreEqual(_xmlErrors.Count,0);
}
void ValidationEventHandler(object sender, ValidationEventArgs args)
{
_xmlErrors.Add("<" + args.Severity + "> " + args.Message);
}
XMLスキーマまたはDTDに対して検証し、ノードが期待する値を持っていることも確認してください。
出力が期待される標準形式がある場合は、XMLスキーマまたはDTDを作成し、それに対して検証してみませんか。これはデータに依存しないため、柔軟性があります。また、XMLの形成方法を定義することは、システムを設計するときに役立ちます。
一部の商用xmlパーサーが正しいと想定し、それに対してxmlコードを検証してみませんか?何かのようなもの。
Assert.IsTrue(myDoc.Xml.ParseOK)
それ以外で、徹底したい場合は、自分でパーサーを作成し、xml仕様で必要な各ルールを検証する必要があると思います。
スキーマを使用して検証するもう1つの理由は、XMLノードは明示的に順序付けられていますが、XML属性は順序付けられていないためです。
したがって、次の文字列の比較:
Assert.AreEqual(myDoc.OuterXML(),"big string of XML")
xMLの1つのビットが手動で作成され、他のビットがプログラムで作成された場合に簡単に発生する可能性があるように、属性の順序が異なると失敗します。
XmlSchemaクラスを使用して、XSDスキーマに対して検証します。 System.XMLの下にあると思います。もう1つのオプションは、XMLをオブジェクトに逆シリアル化するシリアル化クラス(XMLSerializer)を作成することです。利点は、構造を暗黙的に検証し、その後、結果のオブジェクトを使用してテストするために値に簡単にアクセスできることです。
DTDを使用して、生成されたxmlの有効性を確認できます。
正しいコンテンツをテストするには、 XMLUnit を選択します。
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 を使用することで解決できます。
このような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);
結果のドキュメントが整形式であることを確認します結果のドキュメントが有効であることを確認します結果のドキュメントが正しいことを確認します。
おそらく、有用なデータからXMLドキュメントを作成しているので、テストの入力を適切にカバーしていることを確認する必要があります。私が見る最も一般的な問題は
したがって、まだ行っていない場合は、XML仕様を確認して、各場所で何が許可されているかを確認する必要があります。
各テストでどの程度の「チェック」が行われるべきかは、すぐにはわかりません。それはあなたの問題空間にあるユニットが何であるかに大きく依存すると思います。各単体テストが、1つのデータがXMLで正しく表現されていることを確認していることは合理的と思われます。この場合、単一のXPathの場所で適切なデータを見つけるという簡単なチェックが最善であるというRobertに同意します。
ドキュメント全体をチェックしたい大規模な自動テストの場合、効果的であることがわかったのは、ドキュメントでもある期待される結果を取得し、XPath式を使用してノードごとに対応するノードを見つけることです。実際のドキュメントで、2つのノードでエンコードされたデータの正しい比較を適用します。
このアプローチでは、通常、最初の障害で中止するのではなく、すべての障害を一度にキャッチする必要があるため、不一致が発生した場所を追跡する方法について注意が必要な場合があります。
もう少し作業を行うことで、特定の要素タイプをテストから免除されているものとして認識したり(タイムスタンプなど)、それらが同等のノードへのポインターであることを検証したり、その他のカスタム検証を行うことができます。
この新しい 承認テスト ライブラリを使用してXMLテストを支援する予定です。
仕事にぴったりのようですが、使った経験がないのでまずは自分で読んでください。