创建可单元测试的API客户端

时间:2016-01-16 15:05:45

标签: php unit-testing testing phpunit

我目前正在构建一个简单的API客户端,它将为远程服务的HTTP API提供一个很好的包装器。我无法弄清楚如何在客户端内部模拟HTTP响应,以使其易于测试。

例如,采用以下示例类:

<?php

class ApiClient
{
    const API_BASEURL = 'https://api.someservice.com/v1';

    protected $applicationId;
    protected $secretKey;

    public function __construct($applicationId, $secretKey)
    {
        $this->applicationId = $applicationId;
        $this->secretKey = $secretKey;
    }

    public function listAccounts()
    {
        $response = \Httpful\Request::get(self::API_BASEURL.'/accounts')
            ->expectsJson()
            ->send();

        return $response->accounts;
    }
}

我希望使用我的客户端的开发人员能够像以下一样使用它:

$client = new ApiClient($applicationId, $secretKey);
$accounts = $client->listAccounts();

在实践中,这很好用。但是我很难对listAccounts()方法进行单元测试,因为它会向硬编码的API_BASEURL发送HTTP请求。显然,我不希望我的测试实际上向远程服务发起网络呼叫。

我认为解决这个问题的一种方法是模拟\Httpful\Request类,使其返回“伪造”响应,而不是实际命中网络。但是如何将该模拟类传递给我的listAccounts()方法?我只是为了测试而无法将其签名更改为listAccounts($mockedRequest = null)

对我来说测试这个的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

通常你会将请求对象注入到类中(通过构造函数参数传递)并删除硬依赖项。但在你的情况下,没有请求对象开始,你可以用模拟替换。 这就是静态方法的问题。如果您想编写单元测试,这个Httpful库似乎不是一个好的选择。

我看到两个选项:

  1. 使用不同的,更适合测试的库,例如Guzzle
  2. 如果不可能,请写一个薄的包装器,如下所示:

    class HttpfulClient
    {
        public function createGetRequest($url)
        {
            return \Httpful\Request::get($url);
        }
    }
    

    然后将此实例传递给ApiClient构造函数并在测试中模拟它。

相关问题