msgraph-sdk-php icon indicating copy to clipboard operation
msgraph-sdk-php copied to clipboard

Need Advice on mocking the sdk for unit and integration tests

Open anthonylex opened this issue 1 year ago • 3 comments

For unit testing a class in out application that uses the sdk there isn't an easy way to mock the sdk parts see code block below. I had a dig aorund in the source and couldnt find anything helpful in regards to this. Though I did stumble onto somthing indicating it uses the guzzle client so I was wondering if there was a way to do this: https://docs.guzzlephp.org/en/stable/testing.html#mock-handler with the sdk? Or if there was any other recomended approach?

I will also need to write integration tests and dont want to be letting it call out the the MS servers so the guzzle mock hadnler or something similar would be very useful.

<?php

use Http\Promise\Promise;
use Microsoft\Graph\Generated\Chats\Item\Messages\MessagesRequestBuilder;
use Microsoft\Graph\Generated\Users\Item\Messages\Item\MessageItemRequestBuilder;
use Microsoft\Graph\Generated\Users\Item\Messages\Item\Value\ContentRequestBuilder;
use Microsoft\Graph\Generated\Users\Item\UserItemRequestBuilder;
use Microsoft\Graph\Generated\Users\UsersRequestBuilder;
use Microsoft\Graph\GraphServiceClient;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\StreamInterface;

class SomeService {
    public function __construct(private GraphServiceClient $client)
    {
    }

    public function run(): void {
        $mimeEmail = $this->client->users()
            ->byUserId('[email protected]')
            ->messages()
            ->byMessageId('SomeMessageId')
            ->content()
            ->get()
            ->wait();

        //do something with $mimeEmail;
    }
}

class SomeServiceTest extends TestCase
{

    public function testComponent(): void
    {
        $graphServiceClient = $this->createMock(GraphServiceClient::class);
        $mockUsersRequestBuilder = $this->createMock(UsersRequestBuilder::class);

        $graphServiceClient->expects(self::once())
            ->method('users')
            ->willReturn($mockUsersRequestBuilder)
        ;

        $userItemRequestBuilder = $this->createMock(UserItemRequestBuilder::class);
        $mockUsersRequestBuilder->expects(self::once())
            ->method('byUserId')
            ->with($this->email)
            ->willReturn($userItemRequestBuilder)
        ;

        $messagesRequestBuilder = $this->createMock(MessagesRequestBuilder::class);

        $userItemRequestBuilder->expects(self::once())
            ->method('messages')
            ->willReturn($messagesRequestBuilder);

        $messageItemRequestBuilder = $this->createMock(MessageItemRequestBuilder::class);

        $messagesRequestBuilder->expects(self::once())
            ->method('byMessageId')
            ->with('SomeMessageId')
            ->willReturn($messageItemRequestBuilder)
        ;

        $contentRequestBuilder = $this->createMock(ContentRequestBuilder::class);

        $messageItemRequestBuilder->expects(self::once())
            ->method('content')
            ->willReturn($contentRequestBuilder)
        ;

        $mimeMessagePromise = $this->createMock(Promise::class);

        $contentRequestBuilder->expects(self::once())
            ->method('get')
            ->willReturn($mimeMessagePromise)
        ;


        $stream = $this->createMock(StreamInterface::class);
        $mimeMessagePromise->expects(self::once())
            ->method('wait')
            ->willReturn($stream)
        ;

        $stream->expects(self::once())
            ->method('getContents')
            ->willReturn('Mime Contents')
        ;

        $service = new SomeService($graphServiceClient);

        $service->run();

        //Do assertions
    }

}

anthonylex avatar Feb 28 '24 16:02 anthonylex

Any suggestions about this?

anthonylex avatar Mar 04 '24 09:03 anthonylex

Hi @anthonylex. Thanks for using this SDK and reaching out. You can initialize the GraphServiceClient using a MockHandler as follows:


    $tokenRequestContext = new ClientCredentialContext(
        'tenantId',
        'clientId',
        'clientSecret'
    );
    $authProvider = new GraphPhpLeagueAuthenticationProvider($tokenRequestContext, ['scopes']);
    $handlerStack = GraphClientFactory::getDefaultHandlerStack(new MockHandler([
        // mock responses

    ]));
    $guzzleConfig = [
       'handler' => $handlerStack
    ];
    $httpClient = GraphClientFactory::createWithConfig($guzzleConfig);
    $requestAdapter = new GraphRequestAdapter($authProvider, $httpClient);
    $graphServiceClient = GraphServiceClient::createWithRequestAdapter($requestAdapter);

Let me know if this helps.

Ndiritu avatar Mar 04 '24 10:03 Ndiritu

Thanks for your reply, Will have a go at implementing this and let you know how I get on.

anthonylex avatar Mar 04 '24 10:03 anthonylex