Lazuli

らずり

Awsクライアントのラッパークラスを作ると結構便利

以前、こんなライブラリつくった。
Aws のクライアントクラスをシュパッと作れるやつ。

AwsClientManager for PHP というライブラリを作った - Lazuli

AwsSDK はそれ単体だけだとなかなか使いづらくテストに利用しにくい。
ラッパークラスを作ってやるとテストが容易になるかもと気付いてやってみたら結構いい感じに収束できた。
たとえば、何かをアップロードするようなクラスを作った場合。

<?php
class Uploader
{
    private $S3;

    public function setS3 ($S3)
    {
        $this->S3 = $S3;
    }

    public function upload ($from_path, $to_path)
    {
        $result = $this->S3->putObject([
            'Bucket' => 'bucket_name',
            'Key' => $to_path,
            'Body' => \Guzzle\Http\EntityBody::factory(fopen($from_path, 'r'))
        ]);
        return $result;
    }
}

色々端折ってるけど upload メソッドにパスを渡してやると S3 にアップロードできるよ!って感じ。
次に S3 用のラッパークラス。

<?php
class S3
{
    private $client;

    public function __construct (\Aws\Ec2\Ec2Client $client)
    {
        $this->client = $client;
    }

    public function putObject ($args)
    {
        try {
            $this->client->putObject($args);
        } catch (\Exception $e) {
            throw $e;
        }
        return true;
    }
}

Ec2Client クラスに委譲してるだけなんだけどコンストラクタでクライアント渡すようにしてる。
この部分をモックにしてあげればテストに使えるようになる。

<?php
class UploaderTest extends PHPUnit_Framework_TestCase
{
    private $uploader;

    private $S3_mock;

    public function setUp ()
    {
        $this->uploader = new Uploader();
        $this->S3_mock = $this->getMock('....');
    }

    /**
     * @test
     */
    public function upload ()
    {
        $this->uploader->setS3($this->S3_mock);
        $result = $this->uploader->upload('/tmp/foo.txt', 'foo.txt');
        $this->assertTrue($result);
    }
}

setS3 にモックを渡してるから AwsSDK のクラスがどうなっていようと気にすることなくテストが出来る。
実コードのときは正しいクライアントクラスを渡してあげればよい。

AwsClientManager for PHP というライブラリを作った - Lazuli

これを使うのならば、

<?php

use S3;
use Acm\Acm;

$from_path = '/tmp/foo.txt';
$to_path = 'foo.txt';

$S3 = new S3(Acm::getS3());
$uploader = new Uploader->setS3($S3);
$uploader->upload($from_path, $to_path);

どやぁ。