John Davidson

php - How to mock a class that depends on class from vendor (AwsClient)

0 comments
Message:


Hi I am trying to write unit tests for a specific case where I have to test a class that is depending on Aws\DynamoDb\DynamoDbClient that comes from aws-sdk-php package.


Here is how my class look like:


use Aws\DynamoDb\DynamoDbClient;
use Aws\Result;

class DynamoDbService implements DynamoDbServiceInterface
{
protected DynamoDbClient $client; // Class from aws-sdk-php

public function __construct(DynamoDbClient $client)
{
$this->client = $client;
}

public function describe(string $tableName): Result
{
$result = $this->client->describeTable([
'TableName' => $tableName
]);

return $result;
}
}

I came up with a solution but it does not actually work:


class DynamoDbServiceTest extends TestCase
{
/**
* @test
*/
public function testDescribe()
{
$client = $this->createMock(DynamoDbClient::class);
$resultMock = $this->createMock(Result::class);

$client
->method('describeTable')
->will($this->returnValue($resultMock));

$dynamoDbService = new DynamoDbService($client);

$result = $dynamoDbService->describe('table_example_name');
$this->assertInstanceOf($result, Result::class);
}
}

My solution gave me an error:


There was 1 error:

1) Tests\Unit\DynamoDbServiceTest::testDescribe
PHPUnit\Framework\MockObject\MethodCannotBeConfiguredException: Trying to configure method "describeTable" which cannot be configured because it does not exist, has not been specified, is final, or is static

/home/project/src/tests/unit/DynamoDbServiceTest.php:21

In the end the problem is mocking an AwsClient class. It does not have a describeTable method, but it is rather called by using magic method __call. How can I get a working solution and mock such a class?



My Answer:
To mock a class that depends on a class from a vendor (such as AwsClient), you can use the following approach:

1. Create a mock of the DynamoDbClient class using the createMock method from PHPUnit.
2. Use the setMethods method to specify the methods that you want to mock on the DynamoDbClient class. In this case, you want to mock the __call method.
3. Use the willReturn method to specify the return value of the __call method when it is called with the 'describeTable' method name.
4. Create a mock of the Result class using the createMock method from PHPUnit.
5. Use the createMock method to create an instance of the DynamoDbService class, passing the mocked DynamoDbClient instance as a constructor argument.
6. Call the describe method on the DynamoDbService instance and assert that the return value is an instance of the Result class.

Here is an updated version of your test case:

php
class DynamoDbServiceTest extends TestCase
{
/**
* @test
*/
public function testDescribe()
{
$client = $this->createMock(DynamoDbClient::class);
$client->expects($this->once())
->method('__call')
->with('describeTable', [['TableName' => 'table_example_name']])
->willReturn($this->createMock(Result::class));

$dynamoDbService = new DynamoDbService($client);

$result = $dynamoDbService->describe('table_example_name');
$this->assertInstanceOf($result, Result::class);
}
}


This approach should allow you to mock the DynamoDbClient class and test the describe method of the DynamoDbService class successfully.

Rate this post

5 of 5 based on 4198 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us