PHPUnit - 模拟S3Client不能正常工作

 手机用户2502937497 发布于 2023-01-11 12:46

库:"aws/aws-sdk-php":"2.*"
PHP版本:PHP 5.4.24(cli)

composer.json

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

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

我们已经制作了一个AwsWrapper来获取功能操作:uploadFile,deleteFile ...
你可以阅读这个类,依赖注入要进行单元测试.
专注于构造函数和内部$ this-> s3Client-> putObject(...)调用uploadFile函数.

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;
  }

} 

测试文件将我们的Injector和S3Client实例作为PhpUnit MockObject.要模拟S3Client,我们必须使用Mock Builder禁用原始构造函数.

要模拟S3Client:

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

要配置内部putObject调用(使用putObject测试的情况抛出S3Exception,但我们在$ this-> returnValue($ expected)中遇到了同样的问题.

要初始化测试类并配置sut:

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

不工作的代码:

$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);

当我们执行我们的测试函数时,注入的S3Client不会抛出异常或返回预期值,总是返回NULL.

使用xdebug,我们已经看到S3Client MockObject配置正确但不能按照will()配置的方式工作.

一个"解决方案"(或一个糟糕的解决方案)可能正在执行S3ClientWrapper,这只会将问题转移到无法使用模拟进行单元测试的其他类.

任何的想法?

UPDATE使用xdebug配置MockObject的屏幕截图: 在此输入图像描述

1 个回答
  • 以下代码按预期工作和传递,因此我认为您不会遇到由PHPUnit或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']);
        }
    }
    

    如果你只是想模拟响应并且不关心模拟/存根对象,你也可以使用Guzzle MockPlugin.

    2023-01-11 12:48 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有