Как проверить схему GraphQL с помощью graphql-ruby?

Моя цель - протестировать типы моей схемы GraphQL в ruby, я использую гем graphql-ruby.

Я не смог найти для этого лучшей практики, поэтому мне интересно, как лучше всего протестировать поля и типы схемы.

Гем рекомендует не тестировать схему напрямую 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

Мой первый подход заключался в использовании хэша fields в типе GraphQL :: Schema :: Object, например:

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, любые критические изменения нарушат набор тестов после обновления.
  • Мы повторяем код, тесты утверждают те же поля в типе.
  • Написание этих тестов утомительно, и это снижает вероятность их написания разработчиками.

person Carlos Martinez    schedule 06.07.2018    source источник


Ответы (3)


Похоже, вы хотите протестировать свою схему, потому что хотите знать, не сломает ли она клиента. В основном вам следует избегать этого.

Вместо этого вы можете использовать такие драгоценные камни, как: graphql-schema_comparator для печати критических изменений.

  1. Я предлагаю выполнить задачу по выгрузке вашей схемы (и зафиксировать ее в своем репо).
  2. Вы можете написать некоторую спецификацию, чтобы проверить, была ли схема дампом - тогда вы убедитесь, что у вас всегда есть актуальный дамп схемы.
  3. Настройте свой CI для сравнения схемы текущей ветки со схемой в главной ветке.
  4. Провалить сборку, если в схеме есть опасные или критические изменения.
  5. Вы даже можете сгенерировать журнал изменений схемы с помощью схемы-компаратора;) Или вы даже можете использовать Slack-уведомления для отправки туда любых изменений схемы, чтобы ваша команда могла легко отслеживать любые изменения.
person michal.samluk    schedule 06.07.2018
comment
graphql-schema_comparator выглядит очень красиво, спасибо, что указали на это! - person Carlos Martinez; 06.07.2018

У объекта схемы верхнего уровня есть метод #execute. Вы можете использовать это для написания тестов вроде

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, но это делегирует большинство вещей встроенному хешу.)

person David Maze    schedule 06.07.2018

Я считаю, что лучше по сравнению с первым подходом, который я выбрал, - это использовать тестирование моментальных снимков для схемы GraphQL, вместо того, чтобы тестировать каждую из схем типов / мутаций одну за другой, я создал один тест:

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, см. мой PR здесь.

Гем не позволяет обновлять снимок с помощью одной команды, как в 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 после изменения схемы.

person Carlos Martinez    schedule 06.07.2018