Skip to content

Commit

Permalink
Merge pull request #10 from justbetter/feature/faking-requests
Browse files Browse the repository at this point in the history
Fake requests to Dynamics
  • Loading branch information
VincentBean authored Feb 9, 2023
2 parents d6be309 + 566111b commit 8acdfac
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 18 deletions.
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# Laravel Dynamics Client

This package will connect you to your Microsoft Dynamics web services via OData. Custom web services can easily be
implemented and mapped to your liking.
implemented and mapped to your liking. It uses the [HTTP client](https://laravel.com/docs/master/http-client) of Laravel
which means that you can easily fake requests when writing tests.

The way we interact with OData has been inspired by Laravel's Query Builder.

Expand Down Expand Up @@ -214,6 +215,49 @@ You can run the following command to check if you can successfully connect to Dy
php artisan dynamics:connect {connection?}
```

## Fake requests to Dynamics

When writing tests you may find yourself in the need of faking a request to Dynamics. Luckily, this packages uses the
HTTP client of Laravel to make this very easy.

In order to fake all requests to Dynamics, you can call the method `fake` on any resource.

> The `fake` method will fake **all** requests to Dynamics, not just the endpoint of the used resource.
```php
<?php

use JustBetter\DynamicsClient\OData\BaseResource;

BaseResource::fake();
```

This method will fake the Dynamics configuration and removes sensitive information like usernames and passwords. Only
the company name will remain in order to easily test with multiple connections.

```php
<?php

use Illuminate\Support\Facades\Http;
use JustBetter\DynamicsClient\OData\Pages\Item;

Item::fake();

Http::fake([
'dynamics/ODataV4/Company(\'default\')/Item?$top=1' => Http::response([
'value' => [
[
'@odata.etag' => '::etag::',
'No' => '::no::',
'Description' => '::description::',
],
],
]),
]);

$item = Item::query()->first();
```

## Contributing

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.
Expand Down
32 changes: 15 additions & 17 deletions src/Client/ClientHttpProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@

namespace JustBetter\DynamicsClient\Client;

use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\TransferException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;
use JustBetter\DynamicsClient\Exceptions\DynamicsException;
use JustBetter\DynamicsClient\Exceptions\ModifiedException;
use JustBetter\DynamicsClient\Exceptions\NotFoundException;
use JustBetter\DynamicsClient\Exceptions\UnreachableException;
use Psr\Http\Message\ResponseInterface;
use SaintSystems\OData\GuzzleHttpProvider;
use SaintSystems\OData\HttpRequestMessage;

class ClientHttpProvider extends GuzzleHttpProvider
{
public function send(HttpRequestMessage $request): mixed
public function send(HttpRequestMessage $request): ResponseInterface
{
try {
return parent::send($request);
} catch (RequestException $exception) {
$message = $exception->hasResponse()
? $exception->getResponse()?->getBody()?->getContents()
: $exception->getMessage();
$options = $this->extra_options;

if ($request->body !== null) {
$options['body'] = $request->body;
}

$response = Http::send($request->method, $request->requestUri, $options);
$response->throw();

return $response->toPsrResponse();
} catch (RequestException $exception) {
$message = $exception->getMessage();
$code = $exception->getCode();

/** @var class-string<DynamicsException> $mapping */
$mapping = match ($code) {
404 => NotFoundException::class,
412 => ModifiedException::class,
Expand All @@ -36,12 +40,6 @@ public function send(HttpRequestMessage $request): mixed
$dynamicsException = new $mapping($message, $code, $exception);

throw $dynamicsException->setRequest($request);
} catch (ConnectException $exception) {
throw (new UnreachableException($exception->getMessage(), $exception->getCode(), $exception))
->setRequest($request);
} catch (TransferException $exception) {
throw (new DynamicsException($exception->getMessage(), $exception->getCode(), $exception))
->setRequest($request);
}
}
}
11 changes: 11 additions & 0 deletions src/OData/BaseResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,15 @@ public function newQuery(): QueryBuilder
{
return new QueryBuilder($this->client(), $this->connection, $this->endpoint, static::class);
}

public static function fake(): void
{
foreach (config('dynamics.connections') as $connection => $data) {
config()->set('dynamics.connections.'.$connection.'.base_url', 'dynamics');
config()->set('dynamics.connections.'.$connection.'.version', 'ODataV4');
config()->set('dynamics.connections.'.$connection.'.company', $data['company'] ?? $connection);
config()->set('dynamics.connections.'.$connection.'.username', 'username');
config()->set('dynamics.connections.'.$connection.'.password', 'password');
}
}
}
33 changes: 33 additions & 0 deletions tests/OData/FakeResourceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace JustBetter\DynamicsClient\Tests\OData;

use Illuminate\Support\Facades\Http;
use JustBetter\DynamicsClient\OData\Pages\Item;
use JustBetter\DynamicsClient\Tests\TestCase;

class FakeResourceTest extends TestCase
{
/** @test */
public function it_can_fake_dynamics_requests(): void
{
Item::fake();

Http::fake([
'dynamics/ODataV4/Company(\'default\')/Item?$top=1' => Http::response([
'value' => [
[
'@odata.etag' => '::etag::',
'No' => '::no::',
'Description' => '::description::',
],
],
]),
]);

/** @var Item $item */
$item = Item::query()->first();

$this->assertEquals('::no::', $item['No']);
}
}

0 comments on commit 8acdfac

Please sign in to comment.