Генерация XML для модульного тестирования

Какие стратегии модульного тестирования люди рекомендуют для проверки правильности генерации xml.

Мои текущие тесты кажутся немного примитивными, что-то вроде:

[Test]
public void pseudo_test()
{
   XmlDocument myDOC = new XmlDocument();
   mydoc = _task.MyMethodToMakeXMLDoc();

   Assert.AreEqual(myDoc.OuterXML(),"big string of XML")
}

person Dan    schedule 02.02.2009    source источник


Ответы (13)


Во-первых, как почти все говорят, проверьте 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);

Это позволяет вам проверить не только то, является ли ваш документ семантически корректным, но и то, заполняет ли его метод, создающий его, ожидаемыми значениями.

person Robert Rossney    schedule 02.02.2009

XMLUnit может вам помочь.

person Ionuț G. Stan    schedule 02.02.2009

Другой возможностью может быть использование 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);
    }
person Mike K.    schedule 02.02.2009
comment
XMLUnit уже будет сравнивать xml-файлы и подсчитывать количество различий, если хотите... - person djangofan; 19.11.2009

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");

Обратите внимание, что это работает с LINQ-To-XML, а не с объектом XmlDocument, указанным в исходном вопросе, но лично в эти дни я обнаружил, что использую LINQ-To-XML в качестве первого выбора.

Кроме того, его довольно легко расширять, если вы хотите добавить дополнительные утверждения XML в соответствии с вашими потребностями.

person Holf    schedule 22.10.2012
comment
Новая ссылка здесь. - person Ben Gulapa; 08.12.2016
comment
@BenGulapa Спасибо, ответ обновлен новыми ссылками. - person Holf; 08.12.2016
comment
Новая ссылка на документацию - person SuperRembo; 14.04.2020

Проверьте по XML-схеме или DTD, а также проверьте, что узлы имеют ожидаемые значения.

person svinto    schedule 02.02.2009
comment
+1, и в этом может помочь XmlSerialization С#. - person user7116; 02.02.2009

Если у вас есть стандартный формат, в котором вы ожидаете получить результат, почему бы не создать XML-схему или DTD и не проверить их соответствие этому формату. Это не будет зависеть от данных, поэтому будет гибким. Кроме того, определение того, как может быть сформирован XML, может быть полезным при проектировании вашей системы.

person Jeremy French    schedule 02.02.2009

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

Первое, что нужно сделать, это нормализовать два XML-файла... используя Linq... После того, как оба элемента были нормализованы, вы можете просто сравнить обе строки.

XML нормализуется путем сортировки имен элементов и атрибутов.

person Don Kirkby    schedule 01.04.2011

Проверьте его по схеме XSD, используя класс XmlSchema. Думаю, он найден в System.XML. Другой вариант — написать класс сериализации (XMLSerializer) для десериализации вашего XML в объект. Выигрыш будет заключаться в том, что он будет неявно проверять вашу структуру, и после этого значения могут быть легко доступны для тестирования с использованием полученного объекта.

person Adrian Zanescu    schedule 02.02.2009
comment
есть лучший метод проверки с использованием XMLUnit... - person djangofan; 19.11.2009

Другая причина использования схемы для проверки заключается в том, что, хотя узлы XML упорядочены явно, атрибуты XML — нет.

Итак, ваше сравнение строк:

Assert.AreEqual(myDoc.OuterXML(),"big string of XML")

приведет к ошибке, если атрибуты находятся в другом порядке, что легко может произойти, если один бит XML был создан вручную, а другой - программно.

person merlinc    schedule 02.02.2009

Убедитесь, что результирующий документ правильно сформирован. Убедитесь, что результирующий документ действителен. Убедитесь, что результирующий документ верен.

Предположительно, вы создаете XML-документ из полезных данных, поэтому вам нужно убедиться, что у вас есть правильное покрытие входных данных для ваших тестов. Наиболее распространенные проблемы, которые я вижу, это

  • Неправильно экранированные элементы
  • Неправильно экранированные атрибуты
  • Неправильно экранированные имена элементов
  • Неправильно экранированные имена атрибутов

Поэтому, если вы еще этого не сделали, вам нужно просмотреть спецификацию XML, чтобы узнать, что разрешено в каждом месте.

Сколько «проверок» должно происходить в каждом тесте, не сразу ясно. Я полагаю, это будет во многом зависеть от того, какой юнит находится в вашем проблемном пространстве. Кажется разумным, что каждый модульный тест проверяет правильность представления одного фрагмента данных в XML. В этом случае я согласен с Робертом, что лучше всего просто проверить, что вы нашли нужные данные в одном местоположении XPath.

Для более крупных автоматических тестов, когда вы хотите проверить весь документ, я считаю эффективным иметь ожидаемые результаты, которые также являются документом, и проходить по нему узел за узлом, используя выражения XPath для поиска соответствующего узла. в реальном документе, а затем применяя правильное сравнение данных, закодированных в двух узлах.

При таком подходе вы, как правило, хотите отловить все ошибки сразу, а не прерывать работу при первой ошибке, поэтому вам, возможно, придется проявить хитрость, отслеживая, где произошли несоответствия.

Приложив немного больше усилий, вы можете распознавать определенные типы элементов как исключенные из теста (например, отметку времени), или подтверждать, что они являются указателями на эквивалентные узлы, или... любую пользовательскую проверку, которую вы хотите.

person VoiceOfUnreason    schedule 30.06.2010

Я планирую использовать эту новую библиотеку утверждающего тестирования, чтобы помочь с тестированием XML.

Это выглядит идеально для работы, но сначала прочтите его сами, так как у меня нет опыта его использования.

person tpower    schedule 12.09.2011

почему бы не предположить, что какой-то коммерческий синтаксический анализатор xml является правильным, и не проверить свой xml-код на нем? что-то типа.

Assert.IsTrue(myDoc.Xml.ParseOK)

кроме этого, и если вы хотите быть тщательным, я бы сказал, что вам придется самостоятельно создать синтаксический анализатор и проверить каждое правило, требуемое спецификацией xml.

person Vitor Silva    schedule 02.02.2009

Вы можете использовать DTD для проверки правильности сгенерированного xml.

Чтобы проверить правильность содержимого, я бы выбрал XMLUnit.

Утверждение xml с помощью XMLUnit:

XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);

Diff diff = new Diff(expectedDocument, obtainedDocument);
XMLAssert.assertXMLIdentical("xml invalid", diff, true);

Одна вещь, с которой вы можете столкнуться, это тот факт, что сгенерированный xml может содержать изменяющиеся идентификаторы (атрибуты id/uid и т.п.). Это можно решить с помощью DifferenceListener, когда утверждение сгенерированного 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);
person R. Oosterholt    schedule 04.06.2015