newman / laravel-graphql-test-utils
Laravel GraphQL 测试工具包。帮助您轻松测试 GraphQL 查询和突变。
Requires
- php: ^8.0
- illuminate/contracts: ^8.12|^9.0|^10.0|^11.0
- illuminate/support: ^8.12|^9.0|^10.0|^11.0
- illuminate/testing: ^8.12|^9.0|^10.0|^11.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- larastan/larastan: ^1.0|^2.4
- orchestra/testbench: ^6.0|^7.0|^8.0|^9.0
- phpunit/phpunit: ^8.0|^9.0|^10.0
README
此包帮助您在 TestCases 中测试 GraphQL 查询和突变。它与任何 Laravel GraphQL 服务器一起工作。
要求
- Laravel 8.12+, 9.0+, 10.0+, 11.0
- PHP 8.0+
安装
通过 Composer 需要此包
composer require newman/laravel-graphql-test-utils
📖 文档 & 使用
要开始使用,请将我们的 trait 导入到您的 TestCase 中
<?php namespace Tests; use \Newman\LaravelGraphQLTestUtils\Traits\WithGraphQL; class SomeTest extends TestCase { use WithGraphQL; public function test_it_returns_cars(): void { $response = $this ->graphql() ->setQuery('query ($search: String!) { cars(search: $search) { brand } }') ->setVariables([ 'search' => 'BMW', ]) ->call(); $this->assertEquals([ 'cars' => [ ['brand' => 'BMW'], ], ], $response->json('data')); } }
现在您可以使用我们的可用构建器方法了。
默认断言
默认情况下,我们在获取响应后不为您断言任何内容,但我们提供了注册您的处理程序以自定义此行为的功能。
<?php namespace Tests; use Newman\LaravelGraphQLTestUtils\GraphQLTesting; use Newman\LaravelGraphQLTestUtils\TestResponse; class TestCase extends \Illuminate\Foundation\Testing\TestCase { protected function setUp(): void { parent::setUp(); GraphQlTesting::defaultAssertions(function (TestResponse $response): void { $response->assertOk() ->assertNoGraphQLErrors(); }); } }
构建器方法
setQuery
设置您的 GraphQL 查询。
$this ->graphql() ->setQuery('query { cars { brand } }') ->call();
setVariables
设置多个 GraphQL 变量作为键值对。
$this ->graphql() ->setVariables(['name' => 'John', 'email' => 'my@email.com']) ->call(); // Variables will result as: ['name' => 'John', 'email' => 'my@email.com']
注意:调用 setVariables
将替换之前设置的变量。在这种情况下,您可能希望使用 mergeVariables
。
setVariable
逐个设置变量。
$this ->graphql() ->setVariable('name', 'Oliver') ->setVariable('surname', 'Smith') ->call(); // Variables will result as: ['name' => 'Oliver', 'surname' => 'Smith']
您还可以将其与 setVariables
和 mergeVariables
混合。
$this ->graphql() ->setVariables(['name' => 'James', 'email' => 'my@email.com']) ->setVariable('name', 'Oliver') ->setVariable('surname', 'Smith') ->mergeVariables(['surname' => 'Williams', 'birthday' => '1990-01-01']) ->call(); // Variables will result as: ['name' => 'Oliver', 'email' => 'my@email.com', 'surname' => 'Williams', 'birthday' => '1990-01-01']
注意:使用相同键调用 setVariable
将覆盖之前的值。
mergeVariables
与 setVariables
不同,此方法将先前设置的变量与一对新变量合并。
$this ->graphql() ->setVariables(['name' => 'John', 'email' => 'my@email.com']) ->mergeVariables(['name' => 'James']) ->call(); // Variables will result as: ['name' => 'James', 'email' => 'my@email.com']
schema
指定要使用的 GraphQL 架构(名称)。
$this ->graphql() ->schema('users') ->call();
注意:根据使用的驱动程序,它可能会根据架构自动解析要使用的 HTTP 方法。更多信息。
httpMethod
强制使用特定的 HTTP 方法。默认情况下,它将从架构(如果驱动程序提供)解析,否则将使用 POST
。
$this ->graphql() ->httpMethod('GET') ->call();
driver
您可以选择将此查询切换到默认以外的其他驱动程序。您可能不需要这样做。
$this ->graphql() ->driver('myCustom') ->call();
withToken
将 Bearer 授权令牌添加到请求中。
$this ->graphql() ->withToken('U88Itq0x3yHrhAgCa8mOWuUMKScGAX3zs0xHGnJnvHJoTOmpVTaDX2SVxwxQIsL8') ->call();
withoutToken
从请求中删除授权令牌。
$this ->graphql() ->withoutToken() ->call();
withHeader
将单个标头添加到请求中。
$this ->graphql() ->withHeader('Authorization', 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') ->call();
withHeader
将多个标头添加到请求中。
$this ->graphql() ->withHeaders([ 'X-User-Language' => 'en', 'X-Client' => 'GraphQL-Test', ]) ->call();
modifyRequest
由于我们在基础中使用了 Laravel 的 MakesHttpRequests
Trait,您也可以访问这些函数。
use \Newman\LaravelGraphQLTestUtils\GraphQLRequest; $this ->graphql() ->modifyRequest(function (GraphQLRequest $request) { $request->flushHeaders(); // all MakesHttpRequest public methods can be called. // https://github.com/laravel/framework/blob/9.x/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php }) ->call();
withDefaultAssertions
和 withoutDefaultAssertions
您可能希望单独禁用或重新启用默认断言。
禁用此查询的默认断言
$this ->graphql() ->withoutDefaultAssertions() ->call();
function getBaseBuilder() { return $this->graphql()->withoutDefaultAssertions(); } // I want them to be enabled here. getBaseBuilder() ->withDefaultAssertions() ->call();
call
调用 GraphQL 并返回我们的 TestResponse
类。该函数有两个参数
$this ->graphql() ->call('query ($search: String!) { cars (search: $search) { brand } }', ['search' => 'BMW']);
注意:传递给此函数的变量将合并到现有的变量中。
响应
我们通过一些与 GraphQL 相关的函数/断言扩展了默认的 Laravel 的 Illuminate\Testing\TestResponse
。
assertNoGraphQLErrors
断言没有返回 GraphQL 错误。
assertGraphQLUnauthorized
断言存在未授权错误,格式为相应的 GraphQL 错误。
getQuery
访问请求中使用的查询。
getVariables
访问请求中使用的变量。
getGraphQLErrors
返回 GraphQL 错误的 array
或不存在时返回 null
。
hasGraphQLErrors
确定是否存在任何 GraphQL 错误。
getGraphQLValidationMessages
获取 Laravel 验证消息列表或为空数组时。
[ 'name' => ['This field is required.', 'It must be a string'], // ... ]
getValidationFieldMessages
获取特定字段的 Laravel 验证消息或空数组(当没有或字段不存在时)。
$messages = $response->getValidationFieldMessages('name'); // ['This field is required.', 'It must be a string']
getValidationFieldFirstMessage
获取特定字段的第一个 Laravel 验证消息或 null(当没有或字段不存在时)。
$message = $response->getValidationFieldFirstMessage('name'); // 'This field is required.'
ℹ️ 记住,您也可以访问所有 Illuminate\Testing\TestResponse
函数。
❓ 缺少频繁使用的响应辅助函数?请打开一个新问题。
自定义响应类
此示例向您展示如何使用自定义函数创建自己的 TestResponse 类。
<?php declare(strict_types=1); namespace App\Support; use Newman\LaravelGraphQLTestUtils\TestResponse; class CustomTestResponse extends TestResponse { public function assertDataAlwaysContainsAge(): static { if (!$this->json('data.age')) { Assert::fail('Failed to assert that response contains age key.'); } } }
然后在您的 ServiceProvider(例如 AppServiceProvider
)或 TestCase 中
<?php namespace App\Providers; use App\Support\CustomTestResponse; use Newman\LaravelGraphQLTestUtils\GraphQLTesting; class AppServiceProvider extends \Illuminate\Support\ServiceProvider { public function boot() { GraphQLTesting::useCustomResponseHandler(CustomTestResponse::class); } }
自定义构建器类
此示例向您展示如何使用自定义函数创建自己的 GraphQLBuilder 类。
<?php declare(strict_types=1); namespace App\Support; use App\Models\User; use Newman\LaravelGraphQLTestUtils\GraphQLBuilder; class CustomGraphQLBuilder extends GraphQLBuilder { public function withUser(User $user): static { $this->withToken($user->api_token) return $this; } }
然后在您的 ServiceProvider(例如 AppServiceProvider
)中
<?php namespace App\Providers; use App\Support\CustomGraphQLBuilder; use Newman\LaravelGraphQLTestUtils\Contracts\GraphQLBuilderContract; class AppServiceProvider extends \Illuminate\Support\ServiceProvider { public function register() { $this->app->bind(GraphQLBuilderContract::class, CustomGraphQLBuilder::class); } }
驱动器
驱动器通过从 GraphQL 服务器配置中提取信息来帮助您构建请求,因此您可以省略一些构建器调用。如果您需要的不是我们提供的任何驱动器,您可以编写自己的自定义驱动器。
RebingDriver(默认)
https://github.com/rebing/graphql-laravel
它从配置 graphql.route.prefix
读取 URL 前缀,并根据模式名称从配置中获取第一个 HTTP 方法。
这是默认驱动器。
NullDriver
它使用 /graphql
URL 前缀和 POST
HTTP 方法。
要使用,请在 AppServiceProvider.php
的 boot()
方法中调用 GraphQLTesting::useNullDriver()
。
自定义驱动器
以下是如何实现名为 myCustom
的自定义驱动器的示例。
<?php declare(strict_types=1); namespace App\Support\GraphQLTestingDrivers; use Illuminate\Contracts\Config\Repository as ConfigContract; use Illuminate\Contracts\Container\Container; use Newman\LaravelGraphQLTestUtils\Contracts\DriverContract; class MyCustomDriver implements DriverContract { /** * @var Container */ protected $app; public function __construct(Container $app) { $this->app = $app; } public function getUrlPrefix(): ?string { // ... return your url prefix to GraphQL endpoint. in this case it would be /my-graphql // returning null will fallback to default URL prefix. return 'my-graphql'; } public function getHttpMethodForSchema(string $schemaName): ?string { // ... detect HTTP method from schema name and return it. // below is an example. You may read it from config or resolve any other way. // returning null will fallback to default HTTP method. return $schemaName == 'default' ? 'GET' : 'POST'; } }
然后在您的 ServiceProvider(例如 AppServiceProvider
)中
<?php namespace App\Providers; use App\Support\GraphQLTestingDrivers\MyCustomDriver; use Newman\LaravelGraphQLTestUtils\GraphQLTesting; class AppServiceProvider extends \Illuminate\Support\ServiceProvider { public function boot() { // to activate this driver GraphQlTesting::useDriver('myCustom'); } public function register() { // ... your other bindings $this->app->bind('laravel-graphql-utils-driver:myCustom', MyCustomDriver::class); } }
🤝 贡献
我们感谢您为此包提供合作。
在制作拉取请求时,请确保
- 所有测试都通过:
composer test
- 测试覆盖率没有降低:
composer test-coverage
- 没有 PHPStan 错误:
composer phpstan
- 遵循编码规范:
composer lint
或composer fix-style
以自动修复。