May 31, 2022
0
Level 6
How to test singleton(a class only new once)
Hi,
This is Residence Facade:
class Residence extends Facade
{
protected static function getFacadeAccessor()
{
return 'residence.manager';
}
}
Here is the provider:
class ResidenceServiceProvider extends ServiceProvider implements DeferrableProvider
{
public $singletons = [
'residence.manager' => ResidenceManager::class,
'residence.japan' => ResidenceJapan::class,
'residence.us' => ResidenceUS::class,
'residence.eu' => ResidenceEU::class,
];
public function provides()
{
return [
'residence.manager',
'residence.japan',
'residence.us',
'residence.eu',
];
}
The ResidenceManager Class:
class ResidenceManager
{
protected $app;
public function __construct()
{
$this->app = app();
}
public function make($data)
{
$residenceService = match ($data['location']) {
'japan' => $this->app['residence.japan'],
'us' => $this->app['residence.us'],
'eu' => $this->app['residence.eu'],
default => false
};
if (!$residenceService ) {
return false;
}
return $residenceService->make($data);
}
}
I try to test if
ResidenceJapan::class,ResidenceUS::class, andResidenceEU::classonly new once.
I use spy, bu it give me
Mockery\Exception\InvalidCountException
Method make(<Any Arguments>) from Mockery_0_App_Services_Residence_ResidenceJapan should be called
exactly 1 times but called 3 times.
/**
* @dataProvider residenceSeedProvider
*/
public function test_residence_class_only_new_once($data, $expected)
{
$residence= match ($data['location']) {
'japan' =>
[
'bind' => 'residence.japan',
'class' => ResidenceJapan::class
],
'us' =>
[
'bind' => 'residence.us',
'class' => ResidenceUS::class
],
'eu' => [
'bind' => 'residence.eu',
'class' => ResidenceEU::class
],
default => 'unknown',
};
$spy=$this->spy($residence['class']);
$this->app->instance(
$residence['bind'],
$spy
);
$i = 3;
while ($i > 0) {
//$this->assertNotNull(Residence::make($data));
Residence::make($data);// don't know why the Residence::make($data) return null
$i--;
}
$spy->shouldHaveReceived('make')->once();
}
So I use mock, but it give me
Error
Call to undefined method App\Services\Residence\ResidenceJapan::shouldHaveReceived()
/**
* @dataProvider residenceSeedProvider
*/
public function test_residence_class_only_new_once($data, $expected)
{
$residence= match ($data['location']) {
'japan' =>
[
'bind' => 'residence.japan',
'class' => ResidenceJapan::class
],
'us' =>
[
'bind' => 'residence.us',
'class' => ResidenceUS::class
],
'eu' => [
'bind' => 'residence.eu',
'class' => ResidenceEU::class
],
default => 'unknown',
};
$mock = Mockery::mock($residence['class'], function (MockInterface $mock) use ($expected) {
$mock->shouldReceive('make')->once()->andReturn($expected);
});
$this->app->instance(
$residence['bind'],
$mock
);
$i = 3;
while ($i > 0) {
$this->assertNotNull(Residence::make($data)); // the Residence::make($data) return what I am expected
$i--;
}
$residence['class']::shouldHaveReceived('make')->once();
}
How do I test if ResidenceJapan::class, ResidenceUS::class, and ResidenceEU::class only new once, no matter how many times the Facade Residence::make($data) calls?
Please or to participate in this conversation.