如何使用 graphql-ruby 测试 GraphQL 模式?

Posted

技术标签:

【中文标题】如何使用 graphql-ruby 测试 GraphQL 模式?【英文标题】:How to test a GraphQL schema with graphql-ruby? 【发布时间】:2018-12-14 14:55:46 【问题描述】:

我的目标是在 ruby​​ 中测试我的 GraphQL 模式的类型,我正在使用 graphql-ruby gem。

我找不到任何最佳实践,所以我想知道测试架构的字段和类型的最佳方法是什么。

gem 建议不要直接测试架构 http://graphql-ruby.org/schema/testing.html,但我仍然发现能够知道架构何时意外更改很有价值。

有这样的类型:

module Types
  class DeskType < GraphQL::Schema::Object
    field :id, ID, 'Id of this Desk', null: false
    field :location, String, 'Location of the Desk', null: false
    field :custom_id, String, 'Human-readable unique identifier for this desk', null: false
  end
end

我的第一种方法是在 GraphQL::Schema::Object 类型中使用 fields 哈希,例如:

Types::DeskType.fields['location'].type.to_s => 'String!'

创建一个 RSpec 匹配器,我可以想出如下所示的测试:

RSpec.describe Types::DeskType do
  it 'has the expected schema fields' do
    fields = 
      'id': 'ID!',
      'location': 'String!',
      'customId': 'String!'
    

    expect(described_class).to match_schema_fields(fields)
  end
end

这种方法有一些缺点:

匹配器中的代码取决于类 GraphQL::Schema::Object 的实现,任何重大更改都会在更新后破坏测试套件。 我们在重复代码,测试断言类型中的相同字段。 编写这些测试变得乏味,这使得开发人员不太可能编写它们。

【问题讨论】:

【参考方案1】:

看起来您想测试您的架构,因为您想知道它是否会破坏客户端。基本上你应该避免这种情况。

相反,您可以使用诸如 graphql-schema_comparator 之类的 gem 来打印重大更改。

    我建议有一个 rake 任务来转储您的架构(并将其提交到您的存储库中)。 您可以编写一些规范来检查架构是否已转储 - 然后您将确保您始终拥有最新的架构转储。 设置您的 CI 以将当前分支的架构与主分支上的架构进行比较。 如果架构有危险或破坏性更改,则构建失败。 您甚至可以使用 schema-comparator 生成 Schema Changelog ;) 或者您甚至可以使用 slack 通知将任何架构更改发送到那里,以便您的团队可以轻松跟踪任何更改。

【讨论】:

graphql-schema_comparator 看起来很不错,谢谢指出!【参考方案2】:

***架构对象有一个#execute method。您可以使用它来编写类似的测试

RSpec.describe MySchema do
  it 'fetches an object' do
    id = 'Zm9vOjE'
    query = <<~GRAPHQL
      query GetObject($id: ID!) 
        node(id: $id)  __typename id 
      
    GRAPHQL
    res = described_class.execute(
      query,
      variables:  id: id 
    )
    expect(res['errors']).to be_nil
    expect(res['data']['node']['__typename']).to eq('Foo')
    expect(res['data']['node']['id']).to eq(id)
  end
end

#execute 方法的返回值将是传统的 HTTP 样式响应,作为字符串键控哈希。 (实际上它是一个GraphQL::Query::Result,但它将大多数事情委托给一个嵌入式哈希。)

【讨论】:

【参考方案3】:

我觉得对我采用的第一种方法的改进是对 GraphQL Schema 使用快照测试,而不是逐个测试每个类型/变异模式,我创建了一个测试:

RSpec.describe MySchema do
  it 'renders the full schema' do
    schema = GraphQL::Schema::Printer.print_schema(MySchema)
    expect(schema).to match_snapshot('schema')
  end
end

此方法使用rspec-snapshot gem 的略微修改版本see my PR here。

gem 不允许您像在 Jest 中那样使用单个命令更新快照,因此我还创建了一个 rake 任务来删除当前快照:

namespace :tests do
  desc 'Deletes the schema snapshot'

  task delete_schema_snapshot: :environment do
    snapshot_path = Rails.root.join('spec', 'fixtures', 'snapshots', 'schema.snap')
    File.delete(snapshot_path) if File.exist?(snapshot_path)
  end
end

有了这个,当架构被修改时,你会得到一个漂亮的 RSpec 差异。

【讨论】:

以上是关于如何使用 graphql-ruby 测试 GraphQL 模式?的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 graphql-ruby 订阅进行简单广播

向 graphql-ruby 实现添加多个过滤器

无法理解使用带有 graphql-ruby gem 的 ActionCable 的 GraphQL 订阅

graphql-ruby:Int 不是定义的输入类型(在 $first 上)

Graphql Ruby 中的参数授权

常见排序算法-----希尔排序