将模拟组件注入控制器-集成测试-cakephp 3

将模拟组件注入控制器-集成测试-cakephp 3,cakephp,phpunit,integration-testing,cakephp-3.0,Cakephp,Phpunit,Integration Testing,Cakephp 3.0,目前,我正在为使用组件的类编写集成测试。因为这个组件使用第三方服务(在我的例子中是AWS S3),所以我想用模拟组件替换这个组件,以避免与第三方服务的任何通信 控制器类的一部分: class AlbumsController extends AppController{ public $components = ['Aws', 'Upload']; // Example of function that uses component public functi

目前,我正在为使用组件的类编写集成测试。因为这个组件使用第三方服务(在我的例子中是AWS S3),所以我想用模拟组件替换这个组件,以避免与第三方服务的任何通信

控制器类的一部分:

class AlbumsController extends AppController{
      public $components = ['Aws', 'Upload'];
      // Example of function that uses component
      public function add(){
            $album->pictures = $this->Aws->transformLinkIntoPresignedUrl($album->pictures);
      }
}
集成测试的一部分:

public function controllerSpy($event){
    parent::controllerSpy($event);
    if (isset($this->_controller)) {
        $this->_controller->Auth->setUser([
            'id' => $this->userId,
            'username' => 'testtesttesttest',
            'email' => 'john@doe.com',
            'first_name' => 'Mark',
            'last_name' => 'van der Laan',
            'uuid' => 'wepoewoweo-ew-ewewpoeopw',
            'sign_in_count' => 1,
            'current_sign_in_ip' => '127.0.0.1',
            'active' => true
        ]);
        // If the component is set, inject a mock
        if($this->_controller->Aws){
            $component = $this->getMock('App\Controller\Component\AwsComponent');
            $component->expects($this->once())
                ->method('transformLinkIntoPresignedUrl')
                ->will($this->returnValue(['link']));
            $this->_controller->Aws = $component;
        }
    }
}

由于这会抛出一个transformLinkIntoPresignedUrl不存在的错误,因此我不确定对于这个特定问题我是否走上了正确的道路。因此,我的问题是如何将模拟/存根组件注入控制器并控制其行为(通过为方法设置固定的返回值)?

当我查看IntegrationTestCase的代码时,我发现您(和我)试图做的事情是不可能的。我能想出的最好办法是:

$this->controller = new AlbumsController();

$this->controller->Aws = $this->createMock(AwsComponent::class);
$this->controller->Aws
    ->expects($this->once())
    ->method('transformLinkIntoPresignedUrl');

$this->controller->add();

但这意味着您必须对Flash、Auth、request和其他您认为理所当然的调用进行模拟,因为控制器只是无效的。在这里,我已经达到了知识的极限。

当我查看IntegrationTestCase的代码时,我发现你(和我)想要做的事情是不可能的。我能想出的最好办法是:

$this->controller = new AlbumsController();

$this->controller->Aws = $this->createMock(AwsComponent::class);
$this->controller->Aws
    ->expects($this->once())
    ->method('transformLinkIntoPresignedUrl');

$this->controller->add();

但这意味着您必须对Flash、Auth、request和其他您认为理所当然的调用进行模拟,因为控制器只是无效的。在这里,我已经达到了我的蛋糕知识的极限。

我想自己做这件事,我目前已经下定决心,集成测试是不可能的。如果您正在执行更多的单元测试方法并直接测试控制器方法,那么mock的创建将起作用,但它似乎无法获得请求,使控制器实例中包含任何mock。另一种有点粗糙的方法是使用一些标志或方法来指示您正在进行测试。然后在实际的控制器代码中,您可以在调用组件之前验证您是否未在测试中。我使用的策略是设置一个IS_PHPUNIT常量,检查它是否已定义并具有值。我想说的是,这并不接近最佳实践,但在试图弥合遗留/未测试代码之间的差距和让一些测试正常工作时,有时会有所帮助

我想自己做这件事,目前我已经下定决心,集成测试不可能做到这一点。如果您正在执行更多的单元测试方法并直接测试控制器方法,那么mock的创建将起作用,但它似乎无法获得请求,使控制器实例中包含任何mock。另一种有点粗糙的方法是使用一些标志或方法来指示您正在进行测试。然后在实际的控制器代码中,您可以在调用组件之前验证您是否未在测试中。我使用的策略是设置一个IS_PHPUNIT常量,检查它是否已定义并具有值。我想说的是,这并不接近最佳实践,但在试图弥合遗留/未测试代码之间的差距和让一些测试正常工作时,有时会有所帮助