PHP单元测试:如何测试外部api的低级别函数


PHP Unit Testing: How to test low level functions of an external api

你好各位,我为XmlRPCApi编写了一个低级别实现,但在测试通信时遇到了麻烦。

这是我的密码。

abstract class BaseClient
{
    protected function call($method, array $params = array())
    {
        $request = xmlrpc_encode_request($method, $parameters);
        $file = file_get_contents($this->getDSN(), false, $context);
        $response = xmlrpc_decode($file);
        if ($response && xmlrpc_is_fault(array($response))) {
            trigger_error("xmlrpc: {$response[faultString]} ({$response[faultCode]})");
        }
        return $response;
    }
}

Client extends BaseClient
{
    public function testCall($msg)
    {
        return $this->call('testMethid', array($msg));
    }
}

这是我的测试。

ClientTest extends PHPUnit_FrameWork_TestCase
{
    public function testTestCall()
    {
        $c = new Client();
        $resp = $c->testCall('Hello World');
        $this->assertEquals('Hello World', $resp);
    }
}

这个测试每次都会崩溃,因为不可能在测试环境中访问api。我看不到模拟和注入call函数的解决方案。我能做什么?也许我的对象结构不好,无法测试以及如何改进这种结构(如果发生这种情况)?

干杯。

由于您正在尝试测试外部API,因此我首先将file_get_contents()调用封装在另一个类中,并将其注入BaseClient。在最简单的形式中,它可能看起来像这样:

class RemoteFileRetriever
{
    public function retrieveFileContents($url)
    {
        // Do some work to create $context
        ...
        // Now grab the file contents
        $contents = file_get_contents($url, false, $context);
        return $contents;
    }
}
abstract class BaseClient
{
    private $fileRetriever;
    public function __construct(RemoteFileRetriever $fileRetriever)
    {
        $this->fileRetriever = $fileRetriever;
    }
    protected function call($method, array $params = array())
    {
        ...
        $file = $this->fileRetriever->retrieveFileContents($this->getDSN());
        ...
    }
}

现在在测试中,您可以使用mock对象作为文件检索器进行注入。例如:

class ClientTest extends PHPUnit_FrameWork_TestCase
{
    public function testTestCall()
    {
        $mockRetriever = new MockRemoteFileRetriever();
        $c = new Client($mockRetriever);
        $resp = $c->testCall('Hello World');
        $this->assertEquals('Hello World', $resp);
    }
}

PHPUnit通常有一些用于嘲讽的内置助手。请参阅PHPUnit的模拟对象。

您不想模拟call函数。

如果你不能设置一个假的服务,那么你想模拟php函数,你可以使用php Namespacing(必须有php 5.3)。然后你可以为你在调用方法中调用的内部php函数创建模拟。

http://www.schmengler-se.de/-php-mocking-built-in-functions-like-time-in-unit-tests

如果你不能做到这一点,测试可能会非常困难。你能创建一个可以用来测试的假api吗?请记住,您实际上并没有测试api的方法,而是试图确保您的代码向api发出请求,并以您想要的方式处理响应。

通常,假设第三方代码已经过测试并正常工作。