草庐IT

PHPUnit - 模拟 S3Client 运行不正常

coder 2024-01-01 原文

库:“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...
您可以阅读该类,使用依赖注入(inject)进行单元测试。
关注构造函数和内部 $this->s3Client->putObject(...) 对 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;
  }

} 

测试文件将我们的 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);

当我们执行我们的测试函数时,注入(inject)的S3Client没有抛出异常也没有返回预期的值,总是返回NULL。

通过 xdebug,我们已经看到 S3Client MockObject 配置正确,但不能像 will() 配置的那样工作。

一个“解决方案”(或一个糟糕的解决方案)可能是做一个 S3ClientWrapper,这只会将问题转移到其他不能用 mock 进行单元测试的类。

有什么想法吗?

更新 使用 xdebug 配置 MockObject 的屏幕截图:

最佳答案

以下代码按预期运行和通过,因此我认为您不会遇到由 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如果您只想模拟响应而不关心模拟/ stub 对象。

关于PHPUnit - 模拟 S3Client 运行不正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24080306/

有关PHPUnit - 模拟 S3Client 运行不正常的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  7. ruby-on-rails - rails : save file from URL and save it to Amazon S3 - 2

    从给定URL下载文件并立即将其上传到AmazonS3的更直接的方法是什么(+将有关文件的一些信息保存到数据库中,例如名称、大小等)?现在,我既不使用Paperclip,也不使用Carrierwave。谢谢 最佳答案 简单明了:require'open-uri'require's3'amazon=S3::Service.new(access_key_id:'KEY',secret_access_key:'KEY')bucket=amazon.buckets.find('image_storage')url='http://www.ex

  8. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  9. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  10. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

随机推荐