Как протестировать схему GraphQL с graphql-ruby? - PullRequest
0 голосов
/ 06 июля 2018

Моя цель - протестировать типы моей схемы 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 matcher, я мог бы придумать тесты, которые выглядят так:

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

Ответы [ 3 ]

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

0 голосов
/ 06 июля 2018

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

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

  1. Я предлагаю иметь грабли для сброса вашей схемы (и зафиксировать ее в репо).
  2. Вы можете написать некоторую спецификацию, чтобы проверить, была ли схема дампом - тогда вы убедитесь, что у вас всегда актуальный дамп схемы.
  3. Настройте ваш CI для сравнения схемы текущей ветви со схемой в главной ветви.
  4. Сбой вашей сборки, если в схеме есть опасные или критические изменения.
  5. Вы даже можете создать журнал изменений схемы, используя схему-компаратор;) Или вы можете даже использовать слабые уведомления, чтобы отправлять туда любые изменения схемы, чтобы ваша команда могла легко отслеживать любые изменения.
0 голосов
/ 06 июля 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 gem, см. Мой 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 после изменения схемы.

...