はじめに
最近、Graphql-rubyでAPIを実装しています。
当然、graphqlのテストを書く必要があるんですが、いろいろ方法がありそうなので忘備録としてまとめておきます。
実際にapiを叩く方法
まず、実際にapiを叩く方法を説明します。
以下が例になります。
RSpec.describe User, type: :request do
describe 'user' do
it '指定したusrが取得できること' do
user = create(:user)
post '/graphql', params: { query: query(id: user.id) }
json = JSON.parse(response.body)
data = json['data']['user']
expect(data).to include(
'id' => user.id
)
end
end
end
def query(id:)
<<~GRAPHQL
query {
user(id: "#{id}"){
id
name
}
}
GRAPHQL
end
end
queryを実際に定義して、ローカルのapiにpostするという実直な実装です。
しかし、これだと以下のようにいくつか面倒な点があります。
- expectするためにいちいちパースとかjson形式で確認するのは面倒
- contextを指定できない(current_userが指定できない)
- query書くの面倒
executeを叩く方法
続いて、executeを直接叩いてやる方法です。
こちらもまずは例から
RSpec.describe User, type: :request do
describe 'user' do
it '指定したusrが取得できること' do
user = create(:user)
# AppSchemaは定義されているスキーマ名に変えてください
ret = AppSchema.execute(query(id: user.id) context:{current_user: user})
data = ret['data']['user']
expect(data).to include(
'id' => user.id
)
end
end
end
def query(id:)
<<~GRAPHQL
query {
user(id: "#{id}"){
id
name
}
}
GRAPHQL
end
end
jsonにパースやレスポンスを受け取って記述がなくなり少しすっきりしました。
また、引数にcontextを渡せるのでテストがしやすいです。
一方、queryを書いたり、json形式からidを抜き出したりするのは面倒です。
特にクエリが複雑化してネストが深くなるとjson形式はかなり不便です。
resolverだけ叩く方法
では、早速例をみてみましょう。
RSpec.describe User, type: :request do
describe 'resolver' do
it 'userが取得できること' do
user = create(:user)
# class_nameはロジックが書かれてるresolveのクラス名
mutation = [class_name].new(field: nil, object: nil, context:{current_user: user})
ret = mutation.resolve(id: user.id)
expect(ret).to eq user
end
end
end
だいぶ、すっきりしました。
見ればわかるかと思いますが、resolveが書いてあるクラスをnewして直接resolveメソッドを読んでいます。この方法ですと、戻り値はuserオブジェクトになるのでテストが非常に書きやすいです。
どれつかう?
自分の場合は、ObjectTypeなどのフロントとのインターフェイスをテストするときにはexecuteを直接呼ぶ方法、それ以外のロジックをテストする場合は、resolverを直接呼ぶ方法を使っています。最初のapiを叩く方法はほとんど使いません。
以上、自分が知ってるテスト方法をまとめてみました。他にも良い方法あるよって人はコメントいただけると嬉しいです。