Ответ 1
Это действительно зависит от того, что вы хотите проверить как "различия".
Сейчас мы используем Microsoft XmlDiff: http://msdn.microsoft.com/en-us/library/aa302294.aspx
Я использую .NET 2.0, а недавнее изменение кода аннулирует мой предыдущий вызов Assert.AreEqual(который сравнивал две строки XML). Только один элемент XML на самом деле отличается от новой кодовой базы, поэтому я надеюсь, что сравнение всех остальных элементов даст мне результат, который я хочу. Сравнение должно выполняться программно, поскольку оно является частью unit test.
Сначала я рассматривал возможность использования нескольких экземпляров XmlDocument. Но потом я нашел это: http://drowningintechnicaldebt.com/blogs/scottroycraft/archive/2007/05/06/comparing-xml-files.aspx
Похоже, что это может сработать, но меня заинтересовала обратная связь с переполнением стека, если есть лучший способ.
Я хотел бы избежать добавления другой зависимости для этого, если это вообще возможно.
Это действительно зависит от того, что вы хотите проверить как "различия".
Сейчас мы используем Microsoft XmlDiff: http://msdn.microsoft.com/en-us/library/aa302294.aspx
Возможно, вы найдете менее хрупким, чтобы разобрать XML в XmlDocument и создать свои вызовы Assert в XPath Query. Вот несколько вспомогательных методов утверждения, которые я часто использую. Каждый из них принимает XPathNavigator, который вы можете получить, вызвав CreateNavigator() в XmlDocument или на любом node, извлеченном из документа. Пример использования:
XmlDocument doc = new XmlDocument( "Testdoc.xml" );
XPathNavigator nav = doc.CreateNavigator();
AssertNodeValue( nav, "/root/foo", "foo_val" );
AssertNodeCount( nav, "/root/bar", 6 )
private static void AssertNodeValue(XPathNavigator nav,
string xpath, string expected_val)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNotNull(node, "Node '{0}' not found", xpath);
Assert.AreEqual( expected_val, node.Value );
}
private static void AssertNodeExists(XPathNavigator nav,
string xpath)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNotNull(node, "Node '{0}' not found", xpath);
}
private static void AssertNodeDoesNotExist(XPathNavigator nav,
string xpath)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNull(node, "Node '{0}' found when it should not exist", xpath);
}
private static void AssertNodeCount(XPathNavigator nav, string xpath, int count)
{
XPathNodeIterator nodes = nav.Select( xpath, nav );
Assert.That( nodes.Count, Is.EqualTo( count ) );
}
Выполнение простого сравнения строк в строке xml
не всегда работает. Почему?
например, оба:
<MyElement></MyElmennt>
и <MyElment/>
равны с точки зрения xml
.
Существуют алгоритмы преобразования, при которых xml
всегда выглядят одинаково, они называются
алгоритмы канонизации. .Net
поддерживает канонизацию.
Я написал небольшую библиотеку с утверждениями для сериализации, источник.
Пример:
[Test]
public void Foo()
{
...
XmlAssert.Equal(expected, actual, XmlAssertOptions.IgnoreDeclaration | XmlAssertOptions.IgnoreNamespaces);
}
Из-за того, что содержимое файла XML может иметь различное форматирование и по-прежнему считаться одним и тем же (с точки зрения DOM), когда вы проверяете равенство, вам нужно определить, какова мера этого равенства, например форматирование игнорируется? мета-данные проигнорированы и т.д. позиционируют важные, много крайних случаев.
Как правило, вы должны создать класс, который определяет ваши правила равенства и использовать его для ваших сравнений, и если ваш класс сравнения реализует интерфейсы IEqualityComparer and/or IEqualityComparer<T>
, то ваш класс может использоваться в кучке встроенных списков фреймов в качестве теста равенства также. Плюс, конечно, у вас может быть столько, сколько вам нужно для измерения равенства по-разному, как того требуют ваши требования.
i.e
IEnumerable<T>.Contains
IEnumerable<T>.Equals
The constructior of a Dictionary etc etc
В итоге я получил результат, который мне нужен, со следующим кодом:
private static void ValidateResult(string validationXml, XPathNodeIterator iterator, params string[] excludedElements)
{
while (iterator.MoveNext())
{
if (!((IList<string>)excludedElements).Contains(iterator.Current.Name))
{
Assert.IsTrue(validationXml.Contains(iterator.Current.Value), "{0} is not the right value for {1}.", iterator.Current.Value, iterator.Current.Name);
}
}
}
Перед вызовом метода я создаю навигатор в экземпляре XmlDocument следующим образом:
XPathNavigator nav = xdoc.CreateNavigator();
Далее я создаю экземпляр XPathExpression, например:
XPathExpression expression = XPathExpression.Compile("/blah/*");
Я вызываю метод после создания итератора с выражением:
XPathNodeIterator iterator = nav.Select(expression);
Я все еще выясняю, как оптимизировать его дальше, но теперь это трюк.