Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

A.K.B's avatar
Level 2

Create Mock with constructor

I am wondering if it is possible to set the constructor when using the mock method

use App\Service;

$this->mock(Service::class, function ($mock) {
    $mock->shouldReceive('process')->once();
});

I know I could do it with MockBuilder like:

$this->getMockBuilder(Service::class)
            ->setConstructorArgs([$arg])
            ->getMock();

But it would be nice if I could set in mock() as well. Thank you in advance

0 likes
3 replies
bugsysha's avatar

Hm, in my mind it is bit conflicting to mock some object and care about it's dependencies. If you want to provide correct dependencies then you can just do $service = new Service($dependency); and call and make assertions against $service->process().

A.K.B's avatar
Level 2

Thank you for your reply. In general, you are right. But in my case, it is a bit different. So, I try to explain the real-world scenario, maybe you/someone could even give me a suggestion about the architecture.

Note: I changed the methods' name and functionality to make it more generic.

In my application, I need to implement a third-party API. This API only provides insert() and delete() func, but on my side, I need to prepare move method for customers as well. To do so, whenever the customer call the move method:

  1. API::delete() is called
  2. If the answer is OK, API::inser() will be called as well

so class body is something like this:

class service
{
	public function __contruct(apiClient $client) {...}

     	public function insert($request) {
		...
		$this->client->performRequest($req);
		...
	}

	public function delete($request) {
		...
		$this->client->performRequest($req);
		...
	}

	public function move($request)
	{
		...
		$response = $this->delete($request);

		if($response == 'OK') {
			$this->insert($request)
		}
		...
	}
}

I would like to write a test for the move(). Obviously, I mocked the apiClient, in normal cases, as you said I create a mock for the apiClient and then I instantiate my class this way: $service = new Service($mockClient), but, here if I mocked apiClient the expected method and andReturn method would have two different values! one for delete and one for insert. Therefor, I decided to use partialMock() for my Service class, so I could mock the not needed methods and with passthru() I could test the move(). Here I need to define the constructor!

If you have any suggestion or totally different idea for implementation I am happy to hear and appreciate

S3C_MM's avatar
/** @var apiClient|MockInterface */
private apiClient $apiClient;

public function setUp(): void
{
    parent::setUp();

    $this->apiClient = Mockery::mock(apiClient::class);
}

public function testMovesWhenDeleteSuccesful(): void
{
    $yourMoveRequest = ...
    $this->apiClient->shouldReceive('performRequest')
        ->with($yourMoveRequest)
        ->twice()
        ->andReturn(
            $responseFromDelete, // 'OK'
            $responseFromInsert,
        );
    $service = new service($this->apiClient);
    $service->move($request);
}

public function testDoesntMoveWhenDeleteFailed(): void
{
    $yourMoveRequest = ...
    $this->apiClient->shouldReceive('performRequest')
        ->with($yourMoveRequest)
        ->once()
        ->andReturn($responseFromDelete); // 'NotOK'
    $service = new service($this->apiClient);
    $service->move($request);
}

Please or to participate in this conversation.