So, I'm trying to write a unit test for a piece of code that uses a facade, and it looks like this:
public function test() {
MYFACADE::doSomething();
}
and in the unit test, I am trying to mock the facade call:
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
The only problem with this is that when Laravel tries to make an instance of underling class for the MYFACADE
, it will of course run the constructor, and right there, is hardcoded database connection call. So without changing my facade, and removing database connection from the constructor of the facade class, is there any way to mock facade call without running the constructor of facade ?
UPDATE: Rest of the setup:
Facade 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');
Service provider:
class MyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('myfacade', function()
{
return new myClasThatDoesSomething();
});
}
}
The underlying class used by facade
class myClasThatDoesSomething
{
public function __construct()
{
// opens db connection here
}
public function doSomething()
{
}
}
example class that uses facade:
class TestClass
{
public function testMethod()
{
$returnValue = MYFACADE::doSomething();
return $returnValue;
}
}
Unit test that checks if the testMethod() returns 'testValue';
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn('testValue');
$instance = new TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
答案 0 :(得分:1)
外墙提供静电"与应用程序服务容器中可用的类的接口。
请确保您的MYFACADE
遵循此模式。没有构造函数,数据库等的空间。如果你测试MYFACADE::doSomething()
,你应该模拟该函数正在使用的所有其他类。
其次,以下一段代码
MYFACADE::shouldReceive('doSomething')
->once()
->andReturn(false);
嘲笑外观本身以测试使用 MYFACADE::doSomething()
的其他内容。它应返回Mockery
的实例,在测试中调用false
的任何地方返回MYFACADE::doSomething()
。
修改强>
Laravel的Facade模拟实现实例化了底层类,它允许使用瘦构造函数测试服务。虽然这是最好的做法,但可能并不总是可行。假设你无法从构造函数中移动数据库连接逻辑,最好的办法是手动模拟服务:
public function testTestMethod()
{
MYFACADE::swap(\Mockery::mock()
->shouldReceive('doSomething')
->once()
->andReturn('testValue')
->getMock()
);
$instance = new \App\TestClass();
$value = $instance->testMethod();
$this->assertEquals('testValue', $value);
}