Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Laravel 5.7 + GraphQL(Test編)

この記事は GraphQL Advent Calendar 2018 24日目の記事です。
今回はLaravelとGraphQLでテストコードを書いてみました。

シリーズ記事

今回のゴール

記事の登録ミューテーション(CreatePostMutation)のテストをします。
GraphQLのテストなので、LaravelのHTTPテスト(FeatureTest)を使います。
HTTPリクエストを作成し、GraphQLのjson結果をテストします。

環境

  • Laravel: 5.7.15
  • PHP: 7.1.19
  • PHPUnit: 7.4.4

プロダクトコード

Postモデル

app\Post.phpEloquent\Model を継承したモデルを用意しています。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'title',
        'content',
    ];

    /**
     * Get the user
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Post型の定義

app/GraphQL/Type/PostType.php Post型がどんなフィールドを持っているか定義します。

<?php

declare(strict_types = 1);

namespace App\GraphQL\Type;

use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as BaseType;
use GraphQL;

class PostType extends BaseType
{
    protected $attributes = [
        'name' => 'PostType',
        'description' => 'post type'
    ];

    public function fields() : array
    {
        return [
            'id' => [
                'type' => Type::id(),
                'description' => 'The id of the post'
            ],
            'user_id' => [
                'type' => Type::id(),
                'description' => 'The user_id of post',
            ],
            'title' => [
                'type' => Type::string(),
                'description' => 'The title of post',
            ],
            'content' => [
                'type' => Type::string(),
                'description' => 'The content of post',
            ],
            'user' => [
                'type' => GraphQL::type('UserType'),
                'description' => 'The user of post',
            ],
        ];
    }
}

CreatePostミューテーション

app/GraphQL/Mutation/CreatePostMutation.php 記事の登録を行うミューテーションです。

<?php

declare(strict_types = 1);

namespace App\GraphQL\Mutation;

use Folklore\GraphQL\Support\Mutation;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
use GraphQL;
use Illuminate\Support\Facades\Hash;
use App\User;
use App\Post;

/**
 * 記事を登録するミューテーション
 */
class CreatePostMutation extends Mutation
{
    /**
     * ミューテーション名の定義と概要
     *
     * @var array
     */
    protected $attributes = [
        'name' => 'CreatePost',
        'description' => 'CreatePost mutation'
    ];

    /**
     * ミューテーションが扱う型を定義
     *
     * @return ObjectType
     */
    public function type() : ObjectType
    {
        return GraphQL::type('PostType');
    }

    /**
     * ミューテーションが取り得る引数を定義
     *
     * @return array
     */
    public function args() : array
    {
        return [
            'user_id' => [
                'type' => Type::id(),
                'rules' => ['required'],
            ],
            'title' => [
                'type' => Type::string(),
                'rules' => ['required', 'string'],
            ],
            'content' => [
                'type' => Type::string(),
                'rules' => ['required', 'string'],
            ],
        ];
    }

    /**
     * ミューテーションに対する実処理
     *
     * @param array $root
     * @param array $args
     * @return Post
     */
    public function resolve($root, $args, $context, ResolveInfo $info) : Post
    {
        $user = User::findOrfail($args['user_id']);

        $post = $user->posts()->create([
            'title' => $args['title'],
            'content' => $args['content'],
        ]);

        return $post;
    }
}

テストコードを書く

さて、いよいよ上記のコードのテストを書きます。

TestCase graphql() 関数を用意する

GraphQLは /graphql へPOSTするオンリーワンのエンドポイントです。
エンドポイントが決まっているため、TestCaseの抽象クラスにgraphqlメソッドを用意しておくと便利です。

<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Foundation\Testing\TestResponse;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    /**
     * GraphQL POST request.
     *
     * @param  string $query
     * @param  array  $variables
     * @param  array  $data
     * @param  array  $headers
     * @return \Illuminate\Foundation\Testing\TestResponse
     */
    protected function graphql(string $query, array $variables = [], array $data = [], array $headers = []): TestResponse
    {
        $data = [
            'query' => $query,
            'variables' => json_encode($variables),
        ] + $data;

        return $this->post('/graphql', $data, $headers);
    }
}

記事の登録するテスト

tests/Feature/ExampleTest.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\User;

class ExampleTest extends TestCase
{
    use RefreshDatabase;

    /**
     * @test
     * @return void
     */
    public function 記事を登録するテスト()
    {
        $query = file_get_contents(__DIR__ . '/CreatePostMutation.gql');

        $user = factory(User::class)->create();

        $variables = [
            'user_id' => $user->id,
            'title' => 'テストタイトル',
            'content' => 'テスト内容',
        ];

        $json = [
            'data' => [
                'CreatePost' => $variables
            ],
        ];

        $response = $this->graphql($query, $variables);
        $response->assertStatus(200)->assertJson($json);
    }
}

tests/Feature/CreatePostMutation.gql

mutation (
  $user_id: ID!
  $title: String!
  $content: String!
) {
  CreatePost (
    user_id: $user_id
    title: $title
    content: $content
  ) {
    user_id
    title
    content
  }
}

テスト実行!

$ ./vendor/bin/phpunit
PHPUnit 7.4.0 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 940 ms, Memory: 22.00MB

OK (2 tests, 3 assertions)

OKが返ってきたらOKです。

クエリーファイルの配置場所

クエリーファイルの配置場所についてはわかりやすいようあえてテストファイルと同じ場所にしましたが、
クライアント側が参考にできるように、クエリーだけをまとめたディレクトリを用意すると良いかなと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?