Php 如何测试内部生成XML的类
目前,我正在测试一个类,该类基于值对象生成XML,通过HTTP发送XML,并将XML响应解析回第二个值对象。在本例中,我想测试生成的XML和基于给定XML的解析值对象 该类看起来像:Php 如何测试内部生成XML的类,php,unit-testing,mocking,phpunit,Php,Unit Testing,Mocking,Phpunit,目前,我正在测试一个类,该类基于值对象生成XML,通过HTTP发送XML,并将XML响应解析回第二个值对象。在本例中,我想测试生成的XML和基于给定XML的解析值对象 该类看起来像: class MyClient { public function send(RequestValues $request) { $document = $this->generateMessage($request); $response = $this->
class MyClient
{
public function send(RequestValues $request)
{
$document = $this->generateMessage($request);
$response = $this->request($document);
return $this->parseResponse($response);
}
protected function generateMessage(RequestValues $request)
{
$document = new DomDocument;
// Do stuff with $request
return $document;
}
public function request(DomDocument $document)
{
$client = $this->getHttpClient();
$client->setRawBody($document->saveXml());
// Configure client
return $client->send();
}
public function parseResponse(Response $response)
{
$parameters = new ResponseValues;
$document = new DomDocument;
$document->loadXml($response->getBody());
// Fill in $parameters
return $parameters;
}
}
我想测试两件事:
RequestValues
参数,生成的XML必须看起来像$string
$object
public function testRequestContainsValidXml()
{
$client = $this->getMock('MyClient', array('request'));
$message = '';
$client->expects($this->once())
->method('request')
->with($this->callback(function($object) use ($message) {
return
($object instanceof DomDocument)
&& ($object->saveXml() === $message);
}));
$request = new DirectoryRequest;
$client->send($request);
}
问题是:如何改进测试,以便可以进行正常的字符串比较?我想让phpunit说“字符串X不等于Y”,这大大简化了调试
这个类的完整代码可以在GitHub上找到。当然,上面的例子是一个简化的版本。下面是实际的课程:
PPS。如果为了测试代码而必须修改代码,这不是问题。我只想保持公共API不变(即调用
ResponseValues send(RequestValues$request)
您的类MyClient
表明它是一个facade。要在UnitTests上下文中测试facade,通常首先需要测试作为该facade的协作者的所有单元
由于您通常模拟的是协作者,而不是被测试的单元,因此您的测试设置看起来是错误的,因为您模拟的是被测试的MyClient
单元,而不是它的协作者
例如:
您想测试MyClient::parseResponse()
方法是否返回预期的ResponseValues
对象。因此,在这种情况下,您将模拟响应
,因为它是协作者
您可能还想模仿其他合作者(responsevalue
),但是您不能,因为它是一个无法注入的隐藏依赖项(您可以通过向MyClient
注入一个工厂来解决这个问题,该工厂可以控制此类responsevalue
的创建)
测试MyClient::parseResponse()
:您可以通过Response
mock注入fixture XML,并在返回值上运行断言
用于测试请求是否包含有效XML的案例(testRequestContainsValidXml()
),我也不认为它应该以如此复杂的形式进行。听起来你这里有一个HTTP客户机,你应该只测试它是否工作,而不关心它是否也能与XML一起工作,因为如果它工作,它也能与XML一起工作。你测试有效XML的原因不是因为你想测试客户机。因此,请将该测试排除在cl之外客户端单元测试
顺便说一句,字符串stuff的断言是:
$this->assertSame($expected, $actual);
Phpunit将向您展示字符串之间的一个很好的差异。其他一些程序员/测试人员在比较XML时也应用了一些XML规范化,以使差异更具可读性。如果您的XML在处理无关紧要的空白方面没有问题,您可能会发现类似Q&a和相关问题在这方面很有用
我希望我能用这一点指出您面临的问题案例,并拓宽您对这个问题的看法。我认为您对当前模拟用法的质疑最为尖锐,因为我给出的示例将模拟完全简化为提供合作者,而不是进行断言。这里只对测试单元进行了假设示例性的
MyClient
到底是什么问题?是比较$object->saveXml()吗==$message
失败了?@silkfire如果$message是正确的,它不会失败并通过。但是,无法看到预期字符串和实际字符串之间的差异。您无法通过单元测试以任何方式对此进行调试,例如,$this->assertEquals($string1,$string2)可以进行调试
。与其说单元测试帮助我理解代码中的bug,不如说它是一个大黑匣子,如果你意外地遇到bug,它并没有真正的帮助。所以问题是(也用粗体表示)如何改进测试。我可以让它通过测试,但问题是当它不通过测试时,要从phpunit返回有意义的消息。可以使用PHP的diff类逐个字符查看差异;然后可以在单元测试中调用diff函数?例如,FineDiff非常好;测试ir工具,利用此处的live类: