Laravel 中的测试条带

Hed*_*dam 5 php unit-testing laravel stripe-payments

我正在 Laravel 中创建一个基于订阅的 SaaS 平台,其中 Laravel Cashier 不适合我的需求。因此,我需要使用 Stripe 库自己实现订阅引擎。

我发现通过挂钩一个Subscription类的创建和删除事件,然后相应地创建或取消一个 Stripe 订阅,很容易实现 Laravel 和 Stripe 之间的连接。

不幸的是,Stripe 库主要基于对某些预定义类(.. like \Stripe\Charge::create())调用静态方法。

这让我很难测试,因为您通常会允许依赖注入某些自定义客户端进行模拟,但是由于 Stripe 库是静态引用的,因此没有要注入的客户端。有什么方法可以创建 Stripe 客户端类等,我可以模拟吗?

小智 5

你好,来自未来!

我只是在研究这个。所有这些类都从 Stripe 的ApiResource类扩展而来,继续挖掘,您会发现当库要发出 HTTP 请求时,它会调用$this->httpClient(). 该httpClient方法返回对名为 的变量的静态引用$_httpClient。方便的是,Stripe 类上还有一个ApiRequestor名为 的静态方法,它接受一个应该实现 Stripe 的setHttpClient对象(该接口仅描述一个名为 的方法)。HttpClient\ClientInterfacerequest

Soooooo,在您的测试中,您可以调用ApiRequestor::setHttpClient它来传递您自己的 http 客户端模拟的实例。然后,每当 Stripe 发出 HTTP 请求时,它都会使用您的模拟而不是默认的CurlClient。然后,您的责任是让您的模拟返回格式良好的 Stripe 式响应,并且您的应用程序将不会变得更明智。

这是我在测试中开始使用的一个非常愚蠢的假货:

<?php

namespace Tests\Doubles;

use Stripe\HttpClient\ClientInterface;

class StripeHttpClientFake implements ClientInterface
{
    private $response;
    private $responseCode;
    private $headers;

    public function __construct($response, $code = 200, $headers = [])
    {
        $this->setResponse($response);
        $this->setResponseCode($code);
        $this->setHeaders($headers);
    }

    /**
     * @param string $method The HTTP method being used
     * @param string $absUrl The URL being requested, including domain and protocol
     * @param array $headers Headers to be used in the request (full strings, not KV pairs)
     * @param array $params KV pairs for parameters. Can be nested for arrays and hashes
     * @param boolean $hasFile Whether or not $params references a file (via an @ prefix or
     *                         CURLFile)
     *
     * @return array An array whose first element is raw request body, second
     *    element is HTTP status code and third array of HTTP headers.
     * @throws \Stripe\Exception\UnexpectedValueException
     * @throws \Stripe\Exception\ApiConnectionException
     */
    public function request($method, $absUrl, $headers, $params, $hasFile)
    {
        return [$this->response, $this->responseCode, $this->headers];
    }

    public function setResponseCode($code)
    {
        $this->responseCode = $code;

        return $this;
    }

    public function setHeaders($headers)
    {
        $this->headers = $headers;

        return $this;
    }

    public function setResponse($response)
    {
        $this->response = file_get_contents(base_path("tests/fixtures/stripe/{$response}.json"));

        return $this;
    }
}

Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :)