тестирование phpunit xml выход - PullRequest
       5

тестирование phpunit xml выход

12 голосов
/ 19 февраля 2012

Я написал API, который получает данные из другого API и преобразует их в XML. Как использовать phpunit для проверки того, что вывод является ожидаемым XML и действителен?

Должен ли я создать образец xml со всеми узлами, а затем проверить выходные данные по нему?

Ответы [ 5 ]

9 голосов
/ 31 августа 2012

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

Есть много способов проверить правильность вывода XML, некоторые проще, чем другие.

Я недавно выполнил сценарий, аналогичный тому, о котором спрашивал ОП в это время.

Если у вас был следующий частичный вывод xml из функции (назовем его $ person-> output ()):

<person>
    <eyes>blue</eyes>
    <hair>
        <style>curly</style>
    </hair>
</person>

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

function testWholeOutput() {

    $person = new person();
    $person->setEyes("blue");
    $person->setHairStyle("curly");

    $this-assertEquals(file_get_contents("data\pregenerated_xml.xml"), $person->output());
}

Тест пройден, все довольны ... однако это не позволяет расширить xml. Дополнительной проблемой является то, что вы в первую очередь тестируете то, что выводите, это может привести к некоторым проблемам в дальнейшем.

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

Кроме того, если тест прерывается, мы не знаем, где он сломался, просто новая строка отличается от старой.

Решение: В phpUnit есть функция для вызова assertTag () (и assertNotTag ()), которая будет проходить через xml и может утверждать, существует ли тег, что это за содержимое, и подтверждать, что он правильно настроен. Что-то вроде следующего не сломается, если в вывод xml будет добавлено больше элементов:

function testOutputPersonHasEyes() {

    $person = new person();
    $person->setEyes("blue");
    $person->setHairStyle("curly");

    $this->assertTag(
        array('tag' => 'person',
        'child' => array('tag' => 'eyes')
            ), 
            $person->output());
    }

assertTag здесь проверяет тег person, у которого есть дочерний тег eyes. Теперь, если вы поменяете местами вывод xml примерно так:

<person>
    <hair>
            <style>curly</style>
    </hair>
    <eyes>blue</eyes>
</person>

Вы все равно пройдете вышеуказанный тест, поскольку это все еще допустимый XML и все еще допустимый вывод для любых сценариев, которые используют этот XML.

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

Для дополнительной функциональности Тобиас Шлитт написал отличную статью о модульном тестировании генерации xml в phpUnit, а также предоставляет другую альтернативу этому, создав объект dom и используя его как обертку вокруг класса testcase и тестируя использование php xPath, а также хорошее объяснение плюсов и минусов в этом.

4 голосов
/ 28 августа 2015

Я бы сделал это.1) ваш класс должен использовать: myClass расширяет PHPUnit_Framework_TestCase, 2) тогда все тесты должны начинаться с функции [test], например, что-то вроде этого:

function testFunction()
{
   $testXml = '<xml><message>Hi there PHP</message></xml>';
   $xml = simplexml_load_string($testXml, 'SimpleXMLElement', LIBXML_NOCDATA);

   if ($xml !== false && isset($xml->message)) {

      //either this
      var_dump($xml->message);
      $this->assertEquals('Hi there PHP', $xml->message);

      //or this, should be stdClass
      $xmlObj = json_decode(json_encode((array) xml), 1);
      var_dump($xmlObj->message);
      $this->assertEquals('Hi there PHP', $xmlObj->message);
   }
}
4 голосов
/ 21 августа 2015

Это можно сделать, используя этот компонент phpunit, phpunit-dom-assertions , который можно установить с помощью composer.

Затем используйте assertSelectEquals() вместо phpunit.assertTag() (теперь не рекомендуется) для проверки содержимого тега.

Итак, для проверки тега eyes внутри person вместо:

$this->assertTag(
    array('tag' => 'person',
    'child' => array('tag' => 'eyes')
        ), 
        $person->output());
}

Сделайте это:

    $this->assertSelectCount(
        'person > eyes', 
        true,
        $person->output()
    );

И чтобы специально искать карие глаза, сделайте следующее:

    $this->assertSelectEquals(
        'person > eyes', 
        'brown',
        true,
        $person->output()
    );
4 голосов
/ 19 февраля 2012

Обычно есть два подхода:

  1. Жесткий код ожидаемых XML в качестве строковых переменных в вашем тестовом классе и использование этих строк для сравнения с фактическим результатом.
  2. Создание ожидаемых XML в качестве обычного файласистемные файлы, все еще принадлежащие вашей кодовой базе (вы рассматриваете их как ресурсы ).В тесте вы загружаете ожидаемый файл и снова сравниваете его с результатом.

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

1 голос
/ 09 апреля 2018

Загрузить строку XML в объект simplexml.

    $object = simplexml_load_string($xml);

Это должен быть действительный объект, если его можно создать.

    $this->assertNotFalse($object);
    $this->assertInstanceOf( \SimpleXMLElement::class, $object);

Проверьте все узлы XML, которые вам нужны в выводе.

    $this->assertObjectHasAttribute("vehicle", $object);
    //...
...