Skip to content

Commit 0125a10

Browse files
authored
Add Log client for integration testing (#24)
1 parent aa22d3e commit 0125a10

File tree

5 files changed

+111
-1
lines changed

5 files changed

+111
-1
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## v0.6.0
11+
12+
### Added
13+
14+
- Add `Log` client for integration testing https://github.com/spawnia/sailor/pull/24
15+
1016
## v0.5.0
1117

1218
### Changed

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ $mock2 = HelloSailor::mock();
213213
assert($mock1 === $mock2); // true
214214
```
215215

216+
### Integration
217+
218+
If you want to perform integration testing for a service that uses Sailor without actually
219+
hitting an external API, you can swap out your client with the `Log` client.
220+
It writes all requests made through Sailor to a file of your choice.
221+
222+
```php
223+
# sailor.php
224+
public function makeClient(): Client
225+
{
226+
return new \Spawnia\Sailor\Client\Log(__DIR__ . '/sailor-requests.log');
227+
}
228+
```
229+
230+
Each request goes on a new line and contains a JSON string that holds the `query` and `variables`:
231+
232+
```json
233+
{"query":"{ foo }","variables":{"bar":42}}
234+
{"query":"mutation { baz }","variables":null}
235+
```
236+
237+
This allows you to perform assertions on the calls that were made.
238+
However, the `Log` client can not know what constitutes a valid response for a given response,
239+
so it always responds with an error.
240+
216241
## Examples
217242

218243
You can find examples of how a project would use Sailor within [examples](examples).

src/Client/Log.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spawnia\Sailor\Client;
6+
7+
use Spawnia\Sailor\Client;
8+
use Spawnia\Sailor\Response;
9+
10+
class Log implements Client
11+
{
12+
public const ERROR_MESSAGE = 'Request went to the Log client. It is only meant for testing and can not produce valid responses.';
13+
14+
protected string $filename;
15+
16+
public function __construct(string $filename)
17+
{
18+
$this->filename = $filename;
19+
}
20+
21+
public function request(string $query, \stdClass $variables = null): Response
22+
{
23+
$log = \Safe\json_encode([
24+
'query' => $query,
25+
'variables' => $variables,
26+
]);
27+
28+
$file = \Safe\fopen($this->filename, 'a');
29+
\Safe\fwrite($file, "{$log}\n");
30+
\Safe\fclose($file);
31+
32+
return Response::fromStdClass((object) [
33+
'errors' => [
34+
(object) [
35+
'message' => self::ERROR_MESSAGE,
36+
],
37+
],
38+
]);
39+
}
40+
}

src/Operation.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ abstract class Operation
2222
*
2323
* @var array<class-string<static>, static&MockInterface>
2424
*/
25-
private static array $mocks = [];
25+
protected static array $mocks = [];
2626

2727
/**
2828
* The configured endpoint the operation belongs to.

tests/Unit/Client/LogTest.php

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spawnia\Sailor\Tests\Unit\Client;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Spawnia\Sailor\Client\Log;
9+
10+
class LogTest extends TestCase
11+
{
12+
const FILENAME = __DIR__.'/LogTest.log';
13+
const EXPECTED_JSON = /** @lang JSON */ '{"query":"{ foo }","variables":{"bar":42}}'."\n";
14+
15+
protected function tearDown(): void
16+
{
17+
if (file_exists(self::FILENAME)) {
18+
\Safe\unlink(self::FILENAME);
19+
}
20+
21+
parent::tearDown();
22+
}
23+
24+
public function testRequest(): void
25+
{
26+
self::assertFileDoesNotExist(self::FILENAME);
27+
28+
$log = new Log(self::FILENAME);
29+
$log->request(/** @lang GraphQL */ '{ foo }', (object) ['bar' => 42]);
30+
31+
$contents = \Safe\file_get_contents(self::FILENAME);
32+
self::assertSame(self::EXPECTED_JSON, $contents);
33+
34+
$log->request(/** @lang GraphQL */ '{ foo }', (object) ['bar' => 42]);
35+
36+
$contents = \Safe\file_get_contents(self::FILENAME);
37+
self::assertSame(self::EXPECTED_JSON.self::EXPECTED_JSON, $contents);
38+
}
39+
}

0 commit comments

Comments
 (0)