PHPUnit 测试 XML 输出

17

我编写了一个API,从另一个API获取数据并将其转换为XML。如何使用phpunit测试输出是否是预期的XML并且有效?

我应该创建一个包含所有节点的样本XML,然后检查输出是否与之匹配吗?

5个回答

10
这是一个搜索结果,我认为它可以得到批准,对于任何遇到测试生成的xml饲料器函数/类问题的人都有帮助。
有很多方法可以测试xml输出是否正确,有些比其他方法更容易。
最近我完成了一个类似于OP在此时所询问的脚本。
如果您从函数(假设称之为$person->output())获得以下部分xml输出:
<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的任何脚本仍然是有效的输出。显然,您需要编写测试来确保内容符合预期,并且其他项目正确,但结构允许更少的误报测试和长期减少工作量,尽管在开发时需要更多的时间。对于额外的功能,Tobias Schlitt撰写了一篇很棒的文章介绍了phpUnit中的xml生成单元测试,并提供了另一种用dom对象创建包装器并使用php xPath进行测试的替代方法,以及对这样做的优缺点的详细解释。

3
从版本4.2开始,assertTag()和assertNotTag()已被弃用。 - Doug Amos
1
@ChrisK,@DougAmos,你们有没有使用PHPUnit的assertTag()的替代方案? - Jodes

5

将XML字符串加载到simplexml对象中。

    $object = simplexml_load_string($xml);

如果一个对象可以实例化,那么它应该是有效的。
    $this->assertNotFalse($object);
    $this->assertInstanceOf( \SimpleXMLElement::class, $object);

检查您在输出中需要的所有XML节点。
    $this->assertObjectHasAttribute("vehicle", $object);
    //...

这是最简单和最清晰的解决方案。 - Robbert van den Bogerd

5
通常有两种方法:
  1. 在测试类中将预期的 XML 嵌入为字符串变量,并使用这些字符串与实际结果进行比较。
  2. 创建预期的 XML 作为常规文件系统文件,但属于您的代码库(您将它们视为 资源)。 在测试中,您加载预期的文件,并再次将其与结果进行比较。
这两种选择都是可行的,但是第一种方法(XML 作为硬编码字符串变量)可能在 XML 较大时有点笨重-最好将它们移到单独的文件中。

5

我会这样做: 1)你的类应该使用:myClass extends PHPUnit_Framework_TestCase, 2)然后所有的测试必须以[test]Function开头,例如像这样:

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
可以使用 phpunit-dom-assertions这个PHPUnit组件,可以使用composer进行安装。
然后使用它的assertSelectEquals()而不是phpunitassertTag()(现已弃用)来测试标记的内容。
因此,要检查person中的eyes标记,而不是:
$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()
    );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接