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 votesComments