Внедрение зависимостей PHP с аргументами конструктора, затрудняющими тестирование - PullRequest
0 голосов
/ 15 июня 2019

Я пытаюсь разобраться в некоторых лучших практиках внедрения зависимостей.Я пытаюсь протестировать класс обслуживания, использующий библиотеку braintree/braintree_php composer.Предположим, у меня есть класс 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 голосов
/ 16 июня 2019

Примите значение по умолчанию в вашем конструкторе по умолчанию:

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,
    ]);
  }
}

Таким образом, вы можете переопределить его для тестирования, но оставить его обратно совместимым в производстве

...