2014-06-06 17 views
8

Thư viện: "AWS/AWS-sdk-php": "2. *"
PHP phiên bản: PHP 5.4.24 (cli)PHPUnit - Mock S3Client không hoạt động tốt

composer.json

{ 
    "require": { 
     "php": ">=5.3.1", 
     "aws/aws-sdk-php": "2.*", 
     ... 
    }, 

    "require-dev": { 
     "phpunit/phpunit": "4.1", 
     "davedevelopment/phpmig": "*", 
     "anahkiasen/rocketeer": "*" 
    }, 
    ... 
} 

Chúng tôi đã tạo AwsWrapper để nhận các hành động chức năng: uploadFile, deleteFile ...
Bạn có thể đọc lớp học, với tiêm phụ thuộc để được kiểm tra đơn vị.
Tập trung vào hàm tạo và bên trong $ this-> s3Client-> putObject (...) gọi hàm uploadFile.

<?php 

namespace app\lib\modules\files; 

use Aws\Common\Aws; 
use Aws\S3\Exception\S3Exception; 
use Aws\S3\S3Client; 
use core\lib\exceptions\WSException; 
use core\lib\Injector; 
use core\lib\utils\System; 

class AwsWrapper 
{ 

    /** 
    * @var \core\lib\Injector 
    */ 
    private $injector; 

    /** 
    * @var S3Client 
    */ 
    private $s3Client; 

    /** 
    * @var string 
    */ 
    private $bucket; 

    function __construct(Injector $injector = null, S3Client $s3 = null) 
    { 
    if($s3 == null) 
    { 
     $aws = Aws::factory(dirname(__FILE__) . '/../../../../config/aws-config.php'); 
     $s3 = $aws->get('s3'); 
    } 
    if($injector == null) 
    { 
     $injector = new Injector(); 
    } 
    $this->s3Client = $s3; 
    $this->bucket = \core\providers\Aws::getInstance()->getBucket(); 
    $this->injector = $injector; 
    } 

    /** 
    * @param $key 
    * @param $filePath 
    * 
    * @return \Guzzle\Service\Resource\Model 
    * @throws \core\lib\exceptions\WSException 
    */ 
    public function uploadFile($key, $filePath) 
    { 
    /** @var System $system */ 
    $system = $this->injector->get('core\lib\utils\System'); 
    $body = $system->fOpen($filePath, 'r'); 
    try { 
     $result = $this->s3Client->putObject(array(
     'Bucket' => $this->bucket, 
     'Key' => $key, 
     'Body' => $body, 
     'ACL' => 'public-read', 
    )); 
    } 
    catch (S3Exception $e) 
    { 
     throw new WSException($e->getMessage(), 201, $e); 
    } 

    return $result; 
    } 

} 

Tệp thử nghiệm có trường hợp Injector và S3Client là PhpUnit MockObject. Để giả sử S3Client, chúng ta phải vô hiệu hóa hàm khởi tạo ban đầu bằng Trình dựng Mock.

Để thử S3Client:

$this->s3Client = $this->getMockBuilder('Aws\S3\S3Client')->disableOriginalConstructor()->getMock(); 

Để cấu hình bên trong putObject gọi (trường hợp để kiểm tra với putObject ném S3Exception, nhưng chúng tôi có cùng một vấn đề với $ this-> returnValue ($ dự kiến)

. init kiểm tra lớp và cấu hình sut: mã

public function setUp() 
    { 
    $this->s3Client = $this->getMockBuilder('Aws\S3\S3Client')->disableOriginalConstructor()->getMock(); 
    $this->injector = $this->getMock('core\lib\Injector'); 
    } 

    public function configureSut() 
    { 
    return new AwsWrapper($this->injector, $this->s3Client); 
    } 

Không làm việc:

$expectedArray = array(
    'Bucket' => Aws::getInstance()->getBucket(), 
    'Key' => $key, 
    'Body' => $body, 
    'ACL' => 'public-read', 
); 
$this->s3Client->expects($timesPutObject) 
    ->method('putObject') 
    ->with($expectedArray) 
    ->will($this->throwException(new S3Exception($exceptionMessage, $exceptionCode))); 
$this->configureSut()->uploadFile($key, $filePath); 

Khi chúng tôi thực hiện chức năng thử nghiệm của chúng tôi, S3Client được tiêm không ném ngoại lệ hoặc trả về giá trị mong đợi, luôn trả về NULL.

Với xdebug, chúng ta đã thấy rằng S3Client MockObject được cấu hình đúng nhưng không hoạt động như được cấu hình theo ý muốn().

Một "giải pháp" (hoặc một giải pháp xấu) có thể đang thực hiện S3ClientWrapper, điều này sẽ chỉ di chuyển vấn đề đến lớp khác mà không thể là đơn vị được thử nghiệm với mocks.

Bất kỳ ý tưởng nào?

CẬP NHẬT Ảnh chụp màn hình trên configure MockObject với Xdebug: enter image description here

Trả lời

10

Các công trình mã sau và đi như mong đợi, vì vậy tôi không nghĩ rằng bạn đang chạy vào bất kỳ hạn chế do PHPUnit hoặc AWS SDK.

<?php 

namespace Aws\Tests; 

use Aws\S3\Exception\S3Exception; 
use Aws\S3\S3Client; 
use Guzzle\Service\Resource\Model; 

class MyTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testMockCanReturnResult() 
    { 
     $model = new Model([ 
      'Contents' => [ 
       ['Key' => 'Obj1'], 
       ['Key' => 'Obj2'], 
       ['Key' => 'Obj3'], 
      ], 
     ]); 

     $client = $this->getMockBuilder('Aws\S3\S3Client') 
      ->disableOriginalConstructor() 
      ->setMethods(['listObjects']) 
      ->getMock(); 
     $client->expects($this->once()) 
      ->method('listObjects') 
      ->with(['Bucket' => 'foobar']) 
      ->will($this->returnValue($model)); 

     /** @var S3Client $client */ 
     $result = $client->listObjects(['Bucket' => 'foobar']); 

     $this->assertEquals(
      ['Obj1', 'Obj2', 'Obj3'], 
      $result->getPath('Contents/*/Key') 
     ); 
    } 

    public function testMockCanThrowException() 
    { 
     $client = $this->getMockBuilder('Aws\S3\S3Client') 
      ->disableOriginalConstructor() 
      ->setMethods(['getObject']) 
      ->getMock(); 
     $client->expects($this->once()) 
      ->method('getObject') 
      ->with(['Bucket' => 'foobar']) 
      ->will($this->throwException(new S3Exception('VALIDATION ERROR'))); 

     /** @var S3Client $client */ 
     $this->setExpectedException('Aws\S3\Exception\S3Exception'); 
     $client->getObject(['Bucket' => 'foobar']); 
    } 
} 

Bạn cũng có thể sử dụng Guzzle MockPlugin nếu bạn chỉ muốn thử phản ứng và không quan tâm đến chế giễu/stubbing các đối tượng.

+0

Với -> setMethods (['putObject']) đang hoạt động OK! Cảm ơn!! –

Các vấn đề liên quan