目前,我正在努力测试一个基于值对象生成XML的类,通过HTTP发送XML并将XML响应解析回第二个值对象。在这种情况下,我想测试生成的 XML 和基于给定 XML 的解析值对象。
该类如下所示:
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
- 给定某个 XML 响应值(将模拟 HTTP 客户端),该
ResponseValues
必须等于$object
我现在正在为 #1 编写一个测试,但我认为我只能通过回调来实现这一点。但是,当测试失败时,回调并没有给我非常有用的信息。只有这条消息:
断言 DOMDocument 对象 () 被指定的回调接受失败。
测试如下所示:
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 上找到。当然,上面的例子是一个简化版本。这是实际的类:https://github.com/juriansluiman/SlmIdealPayment/blob/master/src/SlmIdealPayment/Client/StandardClient.php#L58
.PPS。如果必须更改代码才能对其进行测试,那不是问题。我只想保持公共 API 相同(即调用ResponseValues send(RequestValues $request)
你的类MyClient
表明它是一个门面。要在 UnitTesting 上下文中测试外观,通常首先需要测试作为该外观协作者的所有单元。
正如您通常模拟协作者而不是被测单元一样,您的测试设置看起来是错误的,因为您正在模拟被测试MyClient
单元,但不是协作者。
例如:
您希望测试 MyClient::parseResponse()
方法是否返回预期的 ResponseValues
对象。因此,在这种情况下,您会嘲笑Response
因为它是合作者。
您可能还想嘲笑其他协作者(ResponseValues
),但是您不能,因为它是一个无法注入的隐藏依赖项(您可以通过向可以控制此类ResponseValues
创建的MyClient
工厂注入工厂来解决此问题)。
测试MyClient::parseResponse()
这么多:您将通过Response
模拟注入夹具XML,并在返回值上运行断言。
对于测试请求是否包含有效 XML(testRequestContainsValidXml()
的情况,我认为也不应该以这种复杂的形式完成。听起来你在这里有一个HTTP客户端,你应该只测试它是否有效,而不关心它是否也适用于XML,因为如果它有效,它也适用于XML。测试有效 XML 的原因不是因为要测试客户端。因此,请将该测试排除在客户端单元测试之外。
顺便说一句,字符串内容的断言是:
$this->assertSame($expected, $actual);
Phpunit将向您展示字符串之间的良好差异。其他一些程序员/测试人员在比较XML时也应用了一些XML规范化,以便差异更具可读性。你可能会发现像PHP XML这样的问答如何输出漂亮的格式和相关有用的,如果你的XML没有问题来处理无关紧要的空格。
我希望我能指出你面临的问题案例,并拓宽你对这个问题的看法。我认为你最关键的是批判性地质疑你目前的模拟用法,对于我给出的例子,我已经完全将嘲笑简化为提供合作者,而不是做断言。断言仅在被测单元上完成,这里是示例性MyClient
.