Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Laravel testing doc and reorganize old testing docs #2021

Open
wants to merge 1 commit into
base: 4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ If you are starting a new project, the easiest way to get API Platform up is to

It comes with the API Platform core library integrated with [the Symfony framework](https://symfony.com), [the schema generator](../schema-generator/),
[Doctrine ORM](https://www.doctrine-project.org),
[NelmioCorsBundle](https://github.com/nelmio/NelmioCorsBundle) and [test assertions dedicated to APIs](testing.md).
[NelmioCorsBundle](https://github.com/nelmio/NelmioCorsBundle) and [test assertions dedicated to APIs](../symfony/testing-utilities.md).

[MongoDB](mongodb.md) and [Elasticsearch](elasticsearch.md) can also be easily enabled.

Expand Down
6 changes: 3 additions & 3 deletions core/json-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ docker compose exec php \

In a unit testing context, API Platform does not use the same schema version as the schema used when generating the API documentation. The version used by the documentation is the OpenAPI Schema version and the version used by unit testing is the JSON Schema version.

When [Testing the API](testing.md), JSON Schemas are useful to generate and automate unit testing. API Platform provides specific unit testing functionalities like [`assertMatchesResourceCollectionJsonSchema()`](testing.md#writing-functional-tests) or [`assertMatchesResourceItemJsonSchema()`](testing.md#writing-functional-tests) methods.
When [Testing the API](../symfony/testing-utilities.md), JSON Schemas are useful to generate and automate unit testing. API Platform provides specific unit testing functionalities like [`assertMatchesResourceCollectionJsonSchema()`](../symfony/testing-utilities.md#writing-functional-tests) or [`assertMatchesResourceItemJsonSchema()`](../symfony/testing-utilities.md#writing-functional-tests) methods.
These methods generate a JSON Schema then do unit testing based on the generated schema automatically.

Usually, the fact that API Platform uses a different schema version for unit testing is not a problem, but sometimes you may need to use the [`ApiProperty`](openapi.md#using-the-openapi-and-swagger-contexts) attribute to specify a [calculated field](serialization.md#calculated-field) type by overriding the OpenAPI Schema for the calculated field to be correctly documented.

When you will use [`assertMatchesResourceCollectionJsonSchema()`](testing.md#writing-functional-tests) or [`assertMatchesResourceItemJsonSchema()`](testing.md#writing-functional-tests) functions the unit test will fail on this [calculated field](serialization.md#calculated-field) as the unit testing process doesn't use the `openapi_context` you specified
When you will use [`assertMatchesResourceCollectionJsonSchema()`](../symfony/testing-utilities.md#writing-functional-tests) or [`assertMatchesResourceItemJsonSchema()`](../symfony/testing-utilities.md#writing-functional-tests) functions the unit test will fail on this [calculated field](serialization.md#calculated-field) as the unit testing process doesn't use the `openapi_context` you specified
because API Platform is using the JSON Schema version instead at this moment.

So there is a way to override JSON Schema specification for a specific property in the JSON Schema used by the unit testing process.
Expand Down Expand Up @@ -84,4 +84,4 @@ To generate JSON Schemas programmatically, use the `api_platform.json_schema.sch
## Testing

API Platform provides a PHPUnit assertion to test if a response is valid according to a given Schema: `assertMatchesJsonSchema()`.
Refer to [the testing documentation](testing.md) for more details.
Refer to [the testing documentation](../symfony/testing-utilities.md) for more details.
216 changes: 9 additions & 207 deletions core/testing.md
Original file line number Diff line number Diff line change
@@ -1,211 +1,13 @@
# Testing Utilities
# Testing the API

API Platform provides a set of useful utilities dedicated to API testing.
For an overview of how to test an API Platform app, be sure to read [the testing cookbook first](../symfony/testing.md).
Once your API is up and running, it's crucial to write tests to ensure it is bug-free and to prevent future regressions.
A good practice is to follow a [Test-Driven Development (TDD)](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
approach, where tests are written before the production code.

<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform-security/api-tests?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Test and Assertions screencast"><br>Watch the API Tests & Assertions screencast</a></p>
API Platform provides a set of helpful testing utilities to write unit tests, functional tests, and to create
[test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software).

## The Test HttpClient
## Testing Documentations

API Platform provides its own implementation of the [Symfony HttpClient](https://symfony.com/doc/current/components/http_client.html)'s interfaces, tailored to be used directly in [PHPUnit](https://phpunit.de/) test classes.

While all the convenient features of Symfony HttpClient are available and usable directly, under the hood the API Platform implementation manipulates [the Symfony HttpKernel](https://symfony.com/doc/current/components/http_kernel.html) directly to simulate HTTP requests and responses.
This approach results in a huge performance boost compared to triggering real network requests.
It also allows access to the [Symfony HttpKernel](https://symfony.com/doc/current/components/http_kernel.html) and to all your services via the [Dependency Injection Container](https://symfony.com/doc/current/testing.html#accessing-the-container).
Reuse them to run, for instance, SQL queries or requests to external APIs directly from your tests.

Install the `symfony/http-client` and `symfony/browser-kit` packages to enabled the API Platform test client:

```console
docker compose exec php \
composer require symfony/browser-kit symfony/http-client
```

To use the testing client, your test class must extend the `ApiTestCase` class:

```php
<?php
// api/tests/BooksTest.php

namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

class BooksTest extends ApiTestCase
{
public function testGetCollection(): void
{
$response = static::createClient()->request('GET', '/books');
// your assertions here...
}
}
```

Refer to [the Symfony HttpClient documentation](https://symfony.com/doc/current/components/http_client.html) to discover all the features of the client (custom headers, JSON encoding and decoding, HTTP Basic and Bearer authentication and cookies support, among other things).

Note that you can create your own test case class extending the ApiTestCase. For example to set up a Json Web Token authentication:

```php
<?php
// api/tests/AbstractTest.php
namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Symfony\Bundle\Test\Client;
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;

abstract class AbstractTest extends ApiTestCase
{
private ?string $token = null;

use RefreshDatabaseTrait;

public function setUp(): void
{
self::bootKernel();
}

protected function createClientWithCredentials($token = null): Client
{
$token = $token ?: $this->getToken();

return static::createClient([], ['headers' => ['authorization' => 'Bearer '.$token]]);
}

/**
* Use other credentials if needed.
*/
protected function getToken($body = []): string
{
if ($this->token) {
return $this->token;
}

$response = static::createClient()->request('POST', '/login', ['json' => $body ?: [
'username' => '[email protected]',
'password' => '$3cr3t',
]]);

$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->token = $data['token'];

return $data['token'];
}
}
```

Use it by extending the `AbstractTest` class. For example this class tests the `/users` resource accessibility where only the admin can retrieve the collection:

```php
<?php
namespace App\Tests;

final class UsersTest extends AbstractTest
{
public function testAdminResource()
{
$response = $this->createClientWithCredentials()->request('GET', '/users');
$this->assertResponseIsSuccessful();
}

public function testLoginAsUser()
{
$token = $this->getToken([
'username' => '[email protected]',
'password' => '$3cr3t',
]);

$response = $this->createClientWithCredentials($token)->request('GET', '/users');
$this->assertJsonContains(['description' => 'Access Denied.']);
$this->assertResponseStatusCodeSame(403);
}
}
```

## API Test Assertions

In addition to [the built-in ones](https://phpunit.readthedocs.io/en/latest/assertions.html), API Platform provides convenient PHPUnit assertions dedicated to API testing:

```php
<?php
// api/tests/MyTest.php

namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

class MyTest extends ApiTestCase
{
public function testSomething(): void
{
// static::createClient()->request(...);

// Asserts that the returned JSON is equal to the passed one
$this->assertJsonEquals(/* a JSON document as an array or as a string */);

// Asserts that the returned JSON is a superset of the passed one
$this->assertJsonContains(/* a JSON document as an array or as a string */);

// justinrainbow/json-schema must be installed to use the following assertions

// Asserts that the returned JSON matches the passed JSON Schema
$this->assertMatchesJsonSchema(/* a JSON Schema as an array or as a string */);

// Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform

// For collections
$this->assertMatchesResourceCollectionJsonSchema(YourApiResource::class);
// And for items
$this->assertMatchesResourceItemJsonSchema(YourApiResource::class);
}
}
```

There is also a method to find the IRI matching a given resource and some criteria:

```php
<?php
// api/tests/BooksTest.php

namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

class BooksTest extends ApiTestCase
{
public function testFindBook(): void
{
// Asserts that the returned JSON is equal to the passed one
$iri = $this->findIriBy(Book::class, ['isbn' => '9780451524935']);
static::createClient()->request('GET', $iri);
$this->assertResponseIsSuccessful();
}
}
```

## HTTP Test Assertions

All test assertions provided by Symfony (assertions for status codes, headers, cookies, XML documents...) can be used out of the box with the API Platform test client:

```php
<?php
// api/tests/BooksTest.php

namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

class BooksTest extends ApiTestCase
{
public function testGetCollection(): void
{
static::createClient()->request('GET', '/books');

$this->assertResponseIsSuccessful();
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
```

[Check out the dedicated Symfony documentation entry](https://symfony.com/doc/current/testing/functional_tests_assertions.html).
- If you are using API Platform with Symfony, refer to the [Testing the API with Symfony](/symfony/testing.md) documentation.
- If you are using API Platform with Laravel, refer to the [Testing the API with Laravel](/laravel/testing.md) documentation.
Loading