phplaravelphpunitmockery

Laravel - how to assert with phpunit and mockery what is passed as constructor argument to another service when it is created?


For example I have classes:

class ServiceOne{
  public function testOne($name){
    app(ServiceTwo::class, ['name' => $name])->testTwo();
  }
}

class ServiceTwo{
  __construct(private string $name){}

  public function testTwo(){
    //so domething with $this->name;
  }
}

When I am unit testing ServiceOne->testOne() with phpunit and mockery, I have this code:

    $mock = \Mockery::mock(ServiceTwo::class)
        ->shouldReceive('testTwo')
        ->once()
        ->getMock();

    $this->app->bind(ServiceTwo::class, function () use ($mock) {
        return $mock;
    });

    app(ServiceOne::class)->testOne('testing');

ServiceTwo is mocked and the test code is working, but the problem is that this test will pass no matter if inside testOne() method is:

  public function testOne($name){
    app(ServiceTwo::class, ['name' => $name])->testTwo();
  }

or

  public function testOne($name){
    app(ServiceTwo::class)->testTwo();
  }

or

  public function testOne($name){
    app(ServiceTwo::class, ['name' => ''different])->testTwo();
  }

I want to assert that ServiceTwo was created inside ServiceOne->testOne() with exact param string "testing", any ideas?


Solution

  • You were most of the way there in your solution but missed out in pulling through the app instance and parameters into the closure when binding your mock into the service container.

    If we modify your existing test to pull this in then we will have access to those properties to make an assertion:

    $mock = \Mockery::mock(ServiceTwo::class)
        ->shouldReceive('testTwo')
        ->once()
        ->getMock();
    
    $this->app->bind(ServiceTwo::class, function (Application $app, array $params) use ($mock) {
        $this->assertEquals('testing', $params['name']);
        return $mock;
    });
    
    app(ServiceOne::class)->testOne('testing');