目前,我正在为使用组件的类编写集成测试。由于此组件使用第三方服务(在我的案例中为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不存在的错误,我不确定我是否正在针对这个特定问题走上正轨。因此,我的问题是如何将模拟/存根组件注入控制器并控制其行为(通过为方法设置固定的返回值)?
答案 0 :(得分:0)
当我查看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,请求和其他您认为理所当然的调用进行模拟,因为Controller只是无效。在这里,我达到了蛋糕知识的极限。
答案 1 :(得分:0)
我想自己做,而我目前所确定的是,集成测试无法实现。如果您要执行更多的单元测试方法并直接测试控制器方法,则可以创建模拟,但是似乎无法获得请求,该请求中包含模拟的控制器实例。另一种稍微有点怪异的方法是使用一些标志或方法来表明您正在测试中。然后,在实际的控制器代码中,可以在调用该组件之前验证自己没有处于测试中。我使用了设置IS_PHPUNIT常量并检查其是否已定义并具有值的策略。我会说这不是最佳实践,但有时在尝试弥合遗留/未使用的代码与进行一些测试之间的差距时可能会有所帮助。