使用 Laravel/Lumen 门面进行测试
Testing with Laravel/Lumen facade
所以,我正在尝试为一段使用外观的代码编写单元测试,它看起来像这样:
public function test() {
MYFACADE::doSomething();
}
并且在单元测试中,我试图模拟外观调用:
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
唯一的问题是,当 Laravel 尝试为 MYFACADE
创建底层 class 的实例时,它当然会 运行 构造函数,就在那里,是硬编码的数据库连接调用。因此,在不更改外观并从外观 class 的构造函数中删除数据库连接的情况下,是否有任何方法可以在不 运行 连接外观构造函数的情况下模拟外观调用?
更新:
其余设置:
门面class
class MyFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'myfacade';
}
}
app.php
$app->register(App\Providers\MyServiceProvider::class);
class_alias('App\Facades\MyFacade', 'MYFACADE');
服务提供商:
class MyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('myfacade', function()
{
return new myClasThatDoesSomething();
});
}
}
facade
使用的底层class
class myClasThatDoesSomething
{
public function __construct()
{
// opens db connection here
}
public function doSomething()
{
}
}
使用外观的示例class:
class TestClass
{
public function testMethod()
{
$returnValue = MYFACADE::doSomething();
return $returnValue;
}
}
单元测试检查 testMethod() returns 'testValue';
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn('testValue');
$instance = new TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
Facades provide a "static" interface to classes that are available in the application's service container.
请确保您的 MYFACADE
遵循此模式。没有构造函数、数据库等的空间。如果你测试 MYFACADE::doSomething()
你应该模拟函数正在使用的所有其他 classes。
其次,下面这段代码
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
模拟外观本身以测试 使用 MYFACADE::doSomething()
的其他东西。它应该 return Mockery
的实例,其中 returns false
在测试中调用 MYFACADE::doSomething()
的任何地方。
编辑:
Laravel 的 Facade 模拟实现实例化底层 class,它允许使用瘦构造函数测试服务。尽管这是最佳实践,但并非总是可行。假设您不能从构造函数中移动数据库连接逻辑,最好的办法是手动模拟服务:
public function testTestMethod()
{
MYFACADE::swap(\Mockery::mock()
->shouldReceive('doSomething')
->once()
->andReturn('testValue')
->getMock()
);
$instance = new \App\TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
}
所以,我正在尝试为一段使用外观的代码编写单元测试,它看起来像这样:
public function test() {
MYFACADE::doSomething();
}
并且在单元测试中,我试图模拟外观调用:
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
唯一的问题是,当 Laravel 尝试为 MYFACADE
创建底层 class 的实例时,它当然会 运行 构造函数,就在那里,是硬编码的数据库连接调用。因此,在不更改外观并从外观 class 的构造函数中删除数据库连接的情况下,是否有任何方法可以在不 运行 连接外观构造函数的情况下模拟外观调用?
更新: 其余设置:
门面class
class MyFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'myfacade';
}
}
app.php
$app->register(App\Providers\MyServiceProvider::class);
class_alias('App\Facades\MyFacade', 'MYFACADE');
服务提供商:
class MyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('myfacade', function()
{
return new myClasThatDoesSomething();
});
}
}
facade
使用的底层classclass myClasThatDoesSomething
{
public function __construct()
{
// opens db connection here
}
public function doSomething()
{
}
}
使用外观的示例class:
class TestClass
{
public function testMethod()
{
$returnValue = MYFACADE::doSomething();
return $returnValue;
}
}
单元测试检查 testMethod() returns 'testValue';
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn('testValue');
$instance = new TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
Facades provide a "static" interface to classes that are available in the application's service container.
请确保您的 MYFACADE
遵循此模式。没有构造函数、数据库等的空间。如果你测试 MYFACADE::doSomething()
你应该模拟函数正在使用的所有其他 classes。
其次,下面这段代码
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
模拟外观本身以测试 使用 MYFACADE::doSomething()
的其他东西。它应该 return Mockery
的实例,其中 returns false
在测试中调用 MYFACADE::doSomething()
的任何地方。
编辑:
Laravel 的 Facade 模拟实现实例化底层 class,它允许使用瘦构造函数测试服务。尽管这是最佳实践,但并非总是可行。假设您不能从构造函数中移动数据库连接逻辑,最好的办法是手动模拟服务:
public function testTestMethod()
{
MYFACADE::swap(\Mockery::mock()
->shouldReceive('doSomething')
->once()
->andReturn('testValue')
->getMock()
);
$instance = new \App\TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
}