PepsiIsBetter's avatar

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, and ResidenceEU::class only 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?

0 likes
0 replies

Please or to participate in this conversation.