PHP依赖项注入和构造函数参数使测试变得困难

时间:2019-06-15 20:04:36

标签: php dependency-injection mocking phpunit

我正在尝试了解一些依赖注入最佳实践。我正在尝试测试使用braintree/braintree_php作曲家库的服务类。假设我有一个BraintreeService这样的类:

namespace App\Service;

class BraintreeService
{
    /* @var Braintree_Gateway */
    private $gateway;

    public function __construct()
    {
        $this->gateway = new \Braintree_Gateway([
            'environment' => BRAINTREE_ENVIRONMENT,
            'merchantId' => BRAINTREE_MERCHANT_ID,
            'publicKey' => BRAINTREE_PUBLIC_KEY,
            'privateKey' => BRAINTREE_PRIVATE_KEY,
        ]);
    }

    /*
     * Generate a new client token from Braintree
     *
     * @return string $string
     */
    public function getClientToken() : string
    {
        return $this->gateway->clientToken()->generate();
    }
}

该类的用法如下:

$btService = new \App\Service\BraintreeService();
$token = $btService->getClientToken();

一个明显的问题是,该服务类紧密依赖于Braintree_Gateway。因此,使单元测试BraintreeService变得困难。为了简化测试,我想将Braintree_Gateway移到构造函数参数中。这将允许我在单元测试中模拟Braintree_Gateway类。

但是,据我了解,如果执行此操作,则代码将如下所示:

namespace App\Service;

class BraintreeService
{
    /* @var Braintree_Gateway */
    private $gateway;

    public function __construct(Braintree_Gateway $gateway)
    {
        $this->gateway = $gateway;
    }

    /*
     * Generate a new client token from Braintree
     *
     * @return string $string
     */
    public function getClientToken() : string
    {
        return $this->gateway->clientToken()->generate();
    }
}

该类的用法如下:

$btService = new \App\Service\BraintreeService(
    new \Braintree_Gateway([
        'environment' => BRAINTREE_ENVIRONMENT,
        'merchantId' => BRAINTREE_MERCHANT_ID,
        'publicKey' => BRAINTREE_PUBLIC_KEY,
        'privateKey' => BRAINTREE_PRIVATE_KEY,
    ])
);
$token = $btService->getClientToken();

如果我在整个代码中的多个地方使用此服务,我会觉得这很麻烦。我希望在如何更好地处理依赖关系的同时仍然能够完全测试我的服务类时提供一些建议。谢谢!

1 个答案:

答案 0 :(得分:0)

接受null作为构造函数中的默认值:

public function __construct(Braintree_Gateway $gateway=null) { 
  if(!gateway) { 
    $gateway = new \Braintree_Gateway([
    'environment' => BRAINTREE_ENVIRONMENT,
    'merchantId' => BRAINTREE_MERCHANT_ID,
    'publicKey' => BRAINTREE_PUBLIC_KEY,
    'privateKey' => BRAINTREE_PRIVATE_KEY,
    ]);
  }
}

这样,您可以覆盖它进行测试,但在生产中向后兼容